写了个Linux 回收站脚本,妈妈再也不用担心我的用户主目录了

嘛,写了将近5 个小时,一个没效率的晚上终于给写完了。

嘛,真爽快~

3 年前当root 敢死队的时候rm 了一次根分区,脱队之后又rm 了一次主目录,那之后就写了几个防手滑的C 程序。

不过前几天Slackware 换Archlinux 的时候弄2 了,没备份就mkfs 了,只要用得着什么再重新写什么。

这套脚本感觉做的比那套C 语言中rm 替代指令要好一点。

全彩显示,支持正则表达式搜索,自己感觉健壮性也不是那么不堪一击。


这代码是一边看着《龙与虎》一边大半夜敲的,估计得有点bug,以后发现了再说吧~

话说很久没看到这么喜欢的纯爱番了,大爱逢坂大河~~~~~


最后就像-h 中说的一样,

只是为了自己用的舒坦

Over~


---------已知BUG:--------

1. irm_ 无法在不加路径的情况下删除连字符开头的文件,因为irm_ 没有像传统unix 程序一样的-- 开关

已经修复:现在你不但可以在此类文件名前加路径(例如"./"),也可以使用-- 开关来把-- 后来的参数一律不当作开关处理了。

详情请看irm_ -h。


2. 在一秒中之内删除两个相同文件名的文件时,irm_ 会询问是否覆盖,因为irm_ 的日期只精确到了一秒

已经修复:现在你可以尽情的在极短的时间内删除相同文件名的文件了,你几乎不可能遇到询问覆盖的情况,概率极小。


3. iunrm_ 在清空回收站的时候会忽略隐藏文件

已经修复:现在除了"."、".." 和".recycle_data",其他的都杀无赦。


4. irm_ 当删除一个带斜杠结尾的、不带路径的目录时(irm_ dir/),文件名不会被正确赋值。

已经修复:现在事先去除了可能导致问题的尾部反斜杠。



依旧是先上代码再上图喵了个咪的:

#!/usr/bin/perl
# 程序连同iunrm_ 提供了一个简单的回收站机制
# 用来代替系统的rm 指令.
# 珍爱膝盖,以防中箭,爱生活,爱/dev/sda ;)
#
# PS 扔到/usr/bin/irm_
#       	By: iSpeller

use warnings;
use strict;
use 5.010;

our $recycle = "$ENV{HOME}/.recycle/";
our $data_file = "$recycle".".recycle_data";
our @to_write;	# 将要写入$data_file 的条目

# 冒牌的主函数,主要做一些irm_ ()之前的检查和irm_ ()的参数构造
MAIN: {
    # 只嫁Linux
	die "!!ERROR: Only run on GNU/Linux!\n\t"
            unless $^O =~ /^linux$/i;

    # 没有回收站目录先mkdir 一个
    say "\033[0;31m !!WARN: \033[1;37mDirection ",
		    "[\e[1;31m$recycle\033[1;37m] ",
            "dose not exsit, create it!\033[0;37m"
        and qx/mkdir $recycle/ 
        unless -e -d $recycle;
                
    say "\033[0;31m !!WARN: \033[1;37mData file ",
		    "[\e[1;31m$data_file\033[1;37m]", 
            "dose not exsit, create it!\033[0;37m"
		and qx/touch $data_file/
		unless -e $data_file;
        
    print_help () if (0 == @ARGV or $ARGV[0] =~ /-h/i);
        
    # 构造irm_ () 的参数并且调用之
    my $argv = (join " ", @ARGV);
    my @irm__args;
    push @irm__args, $argv =~ /-.*f/ ? "use_force" : "no_force";

    irm_ (@irm__args);

    exit 0;
}

# sub irm_ ($flag_force)
# @flag_force = qs=w/use_force no_force/
# 处理参数和删除一条龙服务
my $no_switch = 0;
sub irm_ {
    # 参数保留,文件换成新文件名然后调用系统指令mv
    my (@new_name, @old_name);
    # 处理参数
    my $force =  (shift @_) =~ /^use/ ? 1 : 0;    # 只关心f 参数
    
    for (@ARGV) {
        my ($file_name, $file_path);
        my $date = get_date ();

        # 不处理f 参数
        next if (/^-\w*f\w*/);

        # 处理-- 参数但是只处理第一个
        if (!$no_switch and /^--$/) {
            $no_switch = 1;
            say "\033[0;31m !!WARN: \033[1;32m",
                "Will not treat arg as switch now.\033[0;37m"; 
            next;
        }

        # 不处理其他参数、"/"、"/*"和用户指令程序
        # 如果-- 开关打开,那么将"-"开头的参数对待为文件名
        say "\033[0;31m !!WARN: \033[1;37mIgnore arg ",
                "[\e[1;31m$_\033[1;37m]\033[0;37m" 
            and next 
            if (m{^/([^/]+)?$} or m{^/usr/bin.*$} 
                    or (m{^-.*$} and !$no_switch));     
        
        s{/?$}{};       # 去掉最后可能的/
        if (m{/}) {     # 是完整路径
            m{(.*/)(.+)$} and ($file_path, $file_name) = ($1, $2); 
        } else {        # 是不带路径的文件名
            ($file_path, $file_name) = ("", $_);
        }

        # 还要处理一下路径和文件名
        $file_name =~ s{/$}{};  # 最后的斜杠可能造成困扰,如果有就除去掉
        $file_path = $ENV{PWD}.'/'.$file_path if (m{^[^/]});     # 相对路径补全为绝对路径
        # 构造mv 指令的两个参数
        # 新文件名 = 旧文件名+"@"+$date+"_%RAND%_"+随机数
        my ($new_name, $old_name) = (
						"\"".$recycle.$file_name."@".$date."_%RAND%_".int (rand 1000)."\"",
						"\"".$file_path.$file_name."\"");
        push @new_name, $new_name;
        push @old_name, $old_name;
    }
    
    # mv 文件到$recycle
    for my $new_name (@new_name) {
		my $old_name = shift @old_name;
        my $cmd = sprintf "mv %s %s %s", 
                            $force ? "-f" : "-i",
                            $old_name,
                            $new_name;
                            
        my $test_name = $old_name;
        $test_name =~ s/"$//g and $test_name =~ s/^"//g;
		if (-e $test_name) {
			say sprintf "\033[1;31m> \033[1;32m process %s \033[1;37m %s\033[0;37m",
                        $force ? "force" : "",
                        $old_name;
                        qx/$cmd/;
			profile_add ($new_name, $old_name);
		} else {
			say "\033[0;31m !!WARN: \033[1;37mFile ",
				"[\e[1;31m$old_name\033[1;37m] dose not exsit!";
        }
    }
    
    write_profile ();
}

# sub profile_add
# 构造@to_write
sub profile_add {
	my ($new_name, $old_name) = (shift @_, shift @_);
	push @to_write, (join "_\%MOVE_TO\%_", ($new_name, $old_name));
}

# sub write_profile
# 将@to_write 写入$data_file
sub write_profile {
	open (FILE, ">>$data_file")
		or die "!!DIE: Can not read file [$data_file]!";
	say FILE for (@to_write);
	close FILE;
}

# sub get_date
# 返回时间字符串格式:年-月-日-时:分:秒
sub get_date {
    my ($sec, $min, $hour, $mday, $mon, $year_off) = localtime;
    
    my $date = sprintf "%s-%s-%s-%s:%s:%s",
                    $year_off + 1900, be_two (++$mon),
                    be_two ($mday), be_two ($hour),
                    be_two ($min), be_two ($sec);
    return $date;
}

# sub be_two
# 日期格式串每一个部分必须是两位数
# 否则按照算法iunrm_ 会变2
# 算了,按日期查找在iunrm_ 中实现后又删除了
# 敲日期太tm 麻烦了 - -b
sub be_two ($) {
    my $num = shift;
    if ($num =~ /^\d$/) {
        $num = "0".$num;
    }
    return $num;
}

# sub print_help
# 输出一个帮助说明
sub print_help {
    print <<_HELP;
This is \033[1;37mirm_(rm for i)\033[0;37m by iSpeller
Usage: irm_ [Options]... [file]...

        \033[1;32m-f\033[1;37m              Do not ask before overwriting
        \033[1;32m-h|--help\033[1;37m       Show this help

        \033[0;37mOption [file] alse can be [direction].

To remove a file whose name starts with a '-', for example '-foo',
use one of these commands:
    irm_ -- -foo
or:
    irm_ ./-foo

PS: irm_ will ignore unexpect [Options]
    and [file] of "/", "/usr/bin/"
_HELP
    exit 0;
}




#!/usr/bin/perl
# 程序连同irm_ 提供了一个简单的回收站机制
# 珍爱膝盖,防止中箭,爱生活,爱/dev/sda ;)
#
# PS 扔到/usr/bin/iunrm_
#               By: iSpeller

use warnings;
use strict;
use 5.010;

our $recycle = "$ENV{HOME}/.recycle/";
our $data_file = "$recycle".".recycle_data";

# 我是猪函数~~~
MAIN: {
    # 只嫁Linux
    die "ERROR: Only run on GUN/Linux!\n\t"
        unless $^O =~ /^linux/i;

    # 没有$data_file 就不干活
    say "\033[0;31m !!ERROR: \033[1;37mFile ",
            "[\e[1;31m$data_file\033[1;37m] ",
            "dose not exsit!\n",
            "\t\tRun [\e[1;31mirm_\033[1;37m] first!\033[0;37m"
        and exit 1
        unless -e -d $recycle;
    
    # 空参打印帮助
    print_help () if (0 == @ARGV);
    
    # 先检查数据文件
    check_data ();

    # 一个冒牌的switch,用来解析参数
    $_ = shift @ARGV;
    SWITCH: {
        /-h/i and do {		# 参数是-h|--help
            print_help ();
            last SWITCH;
        };
        # -s 会被当作-Sf 看待
        /^-Sf?$/i and do {	# 参数是-Sf. Search File
            search_file("-Sf", @ARGV);
            last SWITCH;
        };
        /^-Sa?$/i and do {	# 参数是-Sa, Search All file
            search_file ("-Sa");
            last SWITCH;
        };
        # -u 会被当作-Uf 看待
        /^-Uf?$/i and do {	# 参数是-Uf, Unrm File
            iunrm_ (@ARGV);
            last SWITCH;
        };
        # -c 也会被当作-Cf 看待
        /^-Cf?$/i and do {  # 参数是-Cf, Clean File
            clean_file ("-Cf", @ARGV);
            last SWITCH;
        };
        /^-Ca?$/i and do {  # 参数是-Ca, Clean All
            clean_file ("-Ca");
            last SWITCH;
        };

        DEFAULT:
            say "\033[0;31m !!WARN: \033[1;37mUnkown Option ",
                    "[\e[1;31m$_\033[1;37m]!\n\t\t",
                    "run iunrm_ -h to show help.\033[0;37m"; 
            exit 1;
    }
    
    # 更新数据文件
    check_data ();
    exit 0;
}

# sub check_data
# 检查$data_file, 记录中文件不存在则删除记录
sub check_data {
	my %data;

	# 读入数据
	open (FILE, "<$data_file")
		or die "Can not open file: $data_file";
	for () {
		my $old_name = $1 if /^"(.+)"_%MOVE_TO%_/;
        my $new_name = $1 if /_%MOVE_TO%_"(.+)"$/;
        $data{$old_name} = $new_name if (defined $old_name);
	}
	close FILE;
	
	# 检查数据
    for (keys %data) {
		delete $data{$_} unless (-e $_);
    }
    
    # 重新写入数据文件
    open (FILE, ">$data_file")
		or die "Can not open file: $data_file";
	for (keys %data) {
		print FILE "\"$_\""."_%MOVE_TO%_"."\"$data{$_}\"\n";
	}
	close FILE;
}

# clean_file
# 删除回收站中和正则匹配的
sub clean_file {
    my $cmd = shift;
    my @args = @_;
    my @files; 
    
    opendir (DIR, $recycle)
        or die "Can not open dir: $recycle!";
    @files = readdir (DIR);
    closedir DIR;
    for (my $count=0; $count<@files; ++$count) {
        $files[$count] = $recycle.$files[$count];
    }
    
    # 空的就直接更新数据文件后返回
    say "\033[1;31mRecycle is empty!\033[0;37m"
        and check_data () 
        and return 
        unless (@files);
    
    # Ca 参数清空回收站
    if ($cmd =~ /-Ca/i) {
        print "\033[1;31mWARN!! Really clean ALL ",
            "files in recycle?(y/n)\033[0;37m";
        exit 1 if ( =~ /n/);
        for (@files) {
            next if m{($recycle)((.)|(..)|(.recycle_data))$};
            qx/rm -r \"$_\"/;
        }
        say "\033[1;32mRecycle has been cleaned!\033[0;37m";
         return;
    }

    # 按照参数正则匹配删除
    for my $file (@files) {
        next if $file =~ m{($recycle)((.)|(..)|(.recycle_data))$};
        for my $arg (@args) {
            my $regax = $arg;
            $regax .= '.*@\d+-\d+-\d+-\d+:\d+:\d+';
            if ($file =~ /$regax/) {
                my $file_name = $1 if ($file =~ m{.*/(.+)@\d+-.+$});
                say "\033[1;31m> \033[1;32mdelete \033[1;37m[$file_name]\033[0;37m";
                qx/rm -r \"$file\"/;
                last;
            }
        }
    }
    
}

# sub search_file
# 查询和正则匹配的文件
sub search_file {
    my $cmd = shift;
    my @files; 
    my @data;
    
    if ($cmd =~ /^-sf/i) {  # 根据文件名匹配
        @files = @ARGV;
    }

    # 读入$data_file
    open (FILE, "<$data_file")
        or die "Can not open file: $data_file!";
    for () {
        my $old_name = $1 if (/^"(.+)"_%MOVE_TO%_/);
        push @data, $old_name if (defined $old_name);
    }
    close FILE;

    # 分析参数并且按照匹配输出
    SWITCH: {
        $cmd =~ /^-sa/i and do {    # 参数-Sa,全部输出
            for (@data) {
                my $file_name = $_;
                $file_name = $1 if ($file_name =~ m{.*/(.+)@\d+-.+$});
                say "\033[1;31m>\033[1;32m found ",
                    "\033[1;37m[$file_name]\033[0;37m";
            }
            last SWITCH;
        };
        $cmd =~ /^-sf/i and do {    # 参数-Sf,按照文件匹配
            my $file;
            for (@data) {
                $file = $1 if (m{/([^/]+@.+)$});
                for (@files) {
					my $regax = $_;
                    $regax =~ s/^\^(.*)\$$/$1/g;
					$regax .= '.*@\d+.+$';
                    if ($file =~ /$regax/) {
                        my $file_name = $1 if ($file =~ /(.+)@\d+-.+$/);
                        say "\033[1;31m>\033[1;32m found ",
                            "\033[1;37m[$file_name]\033[0;37m"; 
                    }
                }
            }
            last SWITCH;
        };
        DEFAULT:
            die "U got a big trouble, boy.";
    }

}

# sub iunrm_
# 恢复符合正则参数的文件
# unrm for i
sub iunrm_ {
    my @files = @_; 
    my %data;
    
    # 从数据文件建立哈希
    open (FILE, "<$data_file")
        or die "Can not open file: $data_file";
    for () {
        my $old_name = $1 if (/^(".+")_%MOVE_TO%_/);
        my $new_name = $1 if (/_%MOVE_TO%_(".+")$/);
        $data{$old_name} = $new_name;
    }
    close FILE;
    
    # 删除匹配的文件名参数
	for my $file (@files) {
        my $regax = $file;
        $regax =~ s/^\^?(.*)\$?$/$1/g;
		for my $file_name (keys %data) {
            # 如果正则匹配            
			if ($data{$file_name} =~ /$regax/) {
                # 构造指令并且执行
                my $cmd = sprintf "mv -i %s %s",
									$file_name,
									$data{$file_name};
                qx/$cmd/ and delete $data{$file_name};
                
                # 打印下删除信息
                my $file_to = $data{$file_name};
                $file_name = $1 if ($file_name =~ m{.*/(.+)});
                $file_name =~ s/^(.+)@\d+-.+"$/$1/g;
				say "\033[1;31m> \033[1;32m process ",
                    "\033[1;37m [$file_name]\033[1;32m to ",
                    "\033[1;37m [$file_to]\033[0;37m";
			}
		}
    }
}

# sub print_help
# 打印iunrm_ 的帮助
sub print_help {
    print <<_HELP;
This is \033[1;37miumrm_(umrm for i)\033[0;37m by iSpeller
Usage: iumrm_ [Options]... [file]...

        \033[1;32m-Sf|-s\033[1;37m          Search by File-name (Regax)
        \033[1;32m-Sa\033[1;37m             Search All
        \033[1;32m-Cf|-c\033[1;37m          Clean File (Regax) of recycle
        \033[1;32m-Ca\033[1;37m             Clean All file of recycle
        \033[1;32m-Uf|-u\033[1;37m          Unrm File-name (Regax)
        \033[1;32m-h|--help\033[1;37m       Show this help

        \033[0;37mOption [file] alse can be [direction].

PS:     You Can Use Perl Regax As [file]...

Example:
        iunrm_ -u "^red-.+" "low\\h.+l"
            ^^ It will unrm file like "red-dog" or "yellow apple" in recycle.
_HELP
    exit 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值