`
dawuafang
  • 浏览: 1091624 次
文章分类
社区版块
存档分类
最新评论

写了个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;
}








分享到:
评论

相关推荐

    入门学习Linux常用必会60个命令实例详解doc/txt

    Linux 是一个真正的多用户操作系统,可以同时接受多个用户登录,还允许一个用户进行多次登录。这是因为Linux和许多版本的Unix一样,提供了虚拟控制台的访问方式,允许用户在同一时间从控制台(系统的控制台是与系统...

    discuz!6.1GBK 版本论坛系统

    【新增】版主管理面板 - 主题回收站,版主可对回收站的主题进行搜索、查看,管理员可进行恢复和彻底删除 【新增】版主管理面板 - 审核用户,管理员可在后台设置某个版主协助进行会员审核 【增强】版主管理面板 - ...

    IIS6.0 IIS,互联网信息服务

    修改主目录:转到“主目录”窗口,再在“本地路径”输入(或用“浏览”按钮选择)好自己网页所在的“D:\Wy”目录。 3.添加首页文件名:转到“文档”窗口,再按“添加”按钮,根据提示在“默认文档名”后输入自己...

    网管教程 从入门到精通软件篇.txt

     下列命令示例向指定设备写入一个新的主引导记录:  fixmbr DeviceHardDisk0  注意 如果不指定 device_name,新的主引导记录将被写入引导设备,即装载主系统的驱动器。 如果系统检测到无效或非标准分区表标记...

    PHP程序开发范例宝典III

    实例089 关闭IE主窗口时,不弹出询问对话框 132 实例090 弹出提示对话框并重定向网页 133 3.8 弹出网页对话框 134 实例091 弹出全屏显示的网页模式对话框 134 实例092 网页拾色器 136 实例093 日期选择器...

    MYSQL常用命令大全

    对于那些已经不用的用户应给予清除,权限过界的用户应及时回收权限,回收权限可以通过更新User表相应字段,也可以使用REVOKE操作。 下面给出本人从其它资料(www.cn-java.com)获得的对常用权限的解释: 全局管理权限...

    MySQL命令大全

    对于那些已经不用的用户应给予清除,权限过界的用户应及时回收权限,回收权限可以通过更新User表相应字段,也可以使用REVOKE操作。 下面给出本人从其它资料(www.cn-java.com)获得的对常用权限的解释: 全局管理...

    vc++ 应用源码包_1

    另外有只打开一个应用程序、CRichEdit的使用、最小到托盘、自动检测在线用户(多播组)等。 freeeim_FreeEIM_企业即时通讯软件源代码2010年8月份最新版 FTP、HTTP 多线程断点续传下载文件 源码 gdiplus应用实例 ...

    vc++ 应用源码包_6

    另外有只打开一个应用程序、CRichEdit的使用、最小到托盘、自动检测在线用户(多播组)等。 freeeim_FreeEIM_企业即时通讯软件源代码2010年8月份最新版 FTP、HTTP 多线程断点续传下载文件 源码 gdiplus应用实例 ...

    vc++ 应用源码包_2

    另外有只打开一个应用程序、CRichEdit的使用、最小到托盘、自动检测在线用户(多播组)等。 freeeim_FreeEIM_企业即时通讯软件源代码2010年8月份最新版 FTP、HTTP 多线程断点续传下载文件 源码 gdiplus应用实例 ...

    vc++ 应用源码包_5

    另外有只打开一个应用程序、CRichEdit的使用、最小到托盘、自动检测在线用户(多播组)等。 freeeim_FreeEIM_企业即时通讯软件源代码2010年8月份最新版 FTP、HTTP 多线程断点续传下载文件 源码 gdiplus应用实例 ...

    vc++ 应用源码包_3

    另外有只打开一个应用程序、CRichEdit的使用、最小到托盘、自动检测在线用户(多播组)等。 freeeim_FreeEIM_企业即时通讯软件源代码2010年8月份最新版 FTP、HTTP 多线程断点续传下载文件 源码 gdiplus应用实例 ...

    超级有影响力霸气的Java面试题大全文档

    例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。 当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望...

    PHP开发实战1200例(第1卷).(清华出版.潘凯华.刘中华).part1

    本书分为5篇15章,共计625个实例和625个经验技巧。每个实例都经作者精心筛选,具有很强的实用性,其中一些实例是开发人员难于寻觅的解决方案。   本书适合PHP的初学者,如高校学生、求职人员作为练习、速查、学习...

    PHP开发实战1200例(第1卷).(清华出版.潘凯华.刘中华).part2

    本书分为5篇15章,共计625个实例和625个经验技巧。每个实例都经作者精心筛选,具有很强的实用性,其中一些实例是开发人员难于寻觅的解决方案。   本书适合PHP的初学者,如高校学生、求职人员作为练习、速查、学习...

    java 面试题 总结

    例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。 当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望...

    vc++ 开发实例源码包

    另外有只打开一个应用程序、CRichEdit的使用、最小到托盘、自动检测在线用户(多播组)等。 FreeBird2011Dlg.h 主对话框类头文件 MultiGroup.h 多播组类头文件 UserLink.h 用户链表类头文件 ListenSocket.h 侦听接口...

Global site tag (gtag.js) - Google Analytics