bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.htmlhtml
rm的悲剧老是发生在不经意之间,因此不管是在shell脚本中仍是交互式bash环境下,执行rm命令时总应该三思三思再三思。也所以,不少人想尽办法防止文件误删除,方法也各类各样。shell
1.默认rm是"rm -i"的别名,ll就是"ls -l"的别名。能够自定义别名来代替某些命令配合某些选项,也能够定义别名组合多个命令。例如:安全
[root@xuexi ~]# alias ls='ls -lA'
这样在列出目录时将同时列出隐藏文件。bash
2.使用不带参数的alias将列出当前shell环境下全部的已定义的别名。函数
3.另外须要说明的是,当别名和命令同名时,将优先执行别名(不然别名就没有意义了),这能够从which的结果中看出:测试
[root@xuexi ~]# which mv alias mv='mv -i' /bin/mv
若是定义的命名名称和原始命令同名(例如定义的别名 ls='ls -l' ),此时若是想要明确使用原始命令,能够删除别名或者使用绝对路径或者使用转义符来还原命令。spa
4.alias命令是临时定义别名,要定义长久生效的别名就将别名定义语句写入/etc/profile或~/.bash_profile或~/.bashrc,第一个对全部用户有效,后面两个对对应用户有效。修改后记得使用source来从新调取这些配置文件。code
5.使用unalias能够临时取消别名。htm
别名这东西定义和使用起来有点模糊,如下面这个别名命令为例,在有的shell脚本的书籍上使用了这样的定义,但倒是错误的,缘由稍后说明。blog
alias rmm='cp $@ ~/backup;rm $@'
该别名的目的是删除文件时先备份到一个目录下,而后再删除。按照man bash里的说明,别名rmm只是第一个cp命令的别名,分号后的rm不是别名的一部分,而是紧跟在别名后的下一行命令。当执行别名rmm时,首先读取别名到分号位置处,而后进行别名扩展,执行完别名命令后,再执行分号后的rm命令。
之因此说上面的命令是错误的命令,问题出在cp的参数"$@",该变量本表示提供的全部参数,但因为cp命令后使用分号分隔并定义了另外一个命令,这使得执行别名命令时,参数没法传递到cp命令上,而只能传递到最后一个命令rm上,也就是说cp后的"$@"是空值。因此该别名等价于:
alias rmm='cp ~/backup;rm $@'
是否真的如此,使用echo测试一番便可。
[root@xuexi ~]# alias rmm='echo cp $@ ~/backup;echo rm $@'
[root@xuexi ~]# rmm /etc/fstab /etc/hosts cp /root/backup rm /etc/fstab /etc/hosts
从上面的结果中看到cp后的"$@"根本就没有进行扩展,而是空值。
那若是别名定义语句中没有使用分号或其余方法定义额外的命令,而是只有一个命令呢?别名必定就能正确工做吗?非也。如下面的例子为例:
[root@xuexi ~]# alias rmm='echo mv -f $@ ~/backup' [root@xuexi ~]# rmm /etc/fstab /etc/hosts mv -f /root/backup /etc/fstab /etc/hosts
发现问题了吗?"$@"是扩展在"~/backup"目录以后的,也就是说下面mv的别名想要替代rm,是没法正常工做的:
alias rm='mv -f $@ ~/backup'
之因此没法正常工做,是由于~/backup也是"$@"的一部分,且是"$@"中最前面的参数。执行下面的命令就知道了:
[root@xuexi ~]# echo mv -f "$@" ~/backup /etc/fstab /etc/hosts mv -f /root/backup /etc/fstab /etc/hosts
从上面的分析能够知道,alias是有其缺陷的,它只适合进行简单的命令和参数替换、补全,想要实现复杂的命令替代有点难度。所以man bash中建议尽可能使用函数来取代别名(For almost every purpose, aliases are superseded by shell functions)。
毫无疑问,写个shell脚本比别名安全、完整多了,这是替代别名的一种方法。而我我的的建议是,在别名的定义语句中使用函数来克服别名的缺陷。
例如,为了让rm安全执行,使用如下两种方法定义别名:
alias rm='copy1(){ /bin/cp -a $@ ~/backup;rm $@; };copy1 $@' alias rm='move1(){ /bin/mv -f $@ ~/backup; };move1 $@'
由于执行别名时的参数只能传递给最后一个命令即copy1或move1函数,但"$@"表明的参数能够传递给函数,让函数中的"$@"获得正确的扩展,因而整个别名都能合理且正确地执行。
或者直接定义一个shell function替代rm。例如向/etc/profile.d/rm.sh文件中写入:
function rm(){ [ -d ~/rmbackup ] || mkdir ~/rmbackup;/bin/mv -f $@ ~/rmbackup; }
chmod +x /etc/profile.d/rm.sh source /etc/profile.d/rm.sh
如此,执行rm命令时,便会执行此处定义的rm函数,使得rm变得更安全。但注意,这样的函数默认没法直接在脚本中使用,除非使用 export -f function_name 导出函数,使其能够被子shell继承。因此,可在/etc/profile.d/rm.sh文件的尾部加上导出语句:
function rm(){ [ -d ~/rmbackup ] || mkdir ~/rmbackup;/bin/mv -f $@ ~/rmbackup; } export -f rm
若是function名和命令名相同,则默认优先执行function,除非使用command明确指定。例如上面定义了rm函数,若是想执行rm命令,除了使用/bin/rm,还能够以下操做:
command rm a.txt
若是是在shell脚本里涉及到rm命令,那么更建议在每次rm以前先cd到那个目录下,而后再rm相对路径,这样至少能保证不出现符号"/"。固然,更重要的是脚本习惯一些编写脚本的规范,印在骨子里那种,就算想出问题也难。