嘛,写了将近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;
}