这个bash函数是如何删除除了某些文件外的所有文件的?

5

我在commandlinefu.com上找到了下面的脚本(该示例不再在线):

rmbut() { 
    local x=("$@")
    IFS=, rm -rf *[!"${x[*]}"] 
}

它删除所有文件和目录,但保留命令行中命名的那些。
请解释以下内容:
- 第一行发生了什么?$@表示所有参数,但为什么要放在括号里? - 我曾经了解过IFS,但从未真正使用它,在这里它的用法是什么? - 通过*[!"${x[*]}"]实现了什么?我不明白如何将其分割成我知道的东西。

你确定 "local x.." 行上的符号是圆括号 () 还是花括号 {} 或方括号 [] 吗?这很重要。此外,从函数的外观来看,它只是删除除了由函数参数指定的基本名称之外的所有文件。 - kvista
是的,括号是正确的。这就是函数的目的,很清楚,我想知道为什么^^ - Alberto Zaccagni
2个回答

4

local x=("$@")创建一个数组,该数组是所有参数的副本($@本身就是一个数组)。

IFS=,将内部字段分隔符设置为逗号。

IFS=, rm -rf *[!"${x[*]}"]表示删除不以任何传递的字符结尾的所有文件。由于*用作数组的索引并且变量被引用,因此它被扩展为单个字符串,并且通常用于分隔数组元素的空格被替换为IFS的内容(在这种情况下是逗号)。

rmbut a b c

解析为rm -rf *[!a,b,c],但这也不会删除以逗号结尾的文件。

认为这个函数可以简化为:

rmbut() { 
    IFS= rm -rf *[!"$*"] 
}

但其行为会略有不同。这个版本将IFS设置为空,因此上面的示例将解析为rm -rf *[!abc],这将删除以逗号结尾的文件(必须显式传递逗号作为参数以保留这些文件)。但是,通过设置IFS=,可以返回该行为(无需复制数组即可完成)。

3

# 创建一个包含函数参数的数组x
local x=("$@")

# 取消IFS变量设置,这使得双引号数组扩展为没有分隔符的单个单词
IFS=

# 删除匹配模式的文件,即不以数组x中的任何字符结尾
rm -rf *[!"${x[*]}"]


@eugene y:你写的是IFS=,但原本应该是IFS=,,你是打错了还是逗号是用来分隔该行中的其他内容和IFS的? - Alberto Zaccagni
@eugene y:你确定吗?我刚刚尝试了一下,从commandlinefu.com复制粘贴过来,它可以正常工作... - Alberto Zaccagni
@Alberto:touch abc bcd cde; rmbut bcd # 仅删除"cde" - Eugene Yarmash
@eugene y:使用该输入确实无法工作,你是对的,无论在IFS之后是否加上,都不行,感谢你指出这一点。 - Alberto Zaccagni
@Dennis:在 OP 链接的页面上,它声明:“删除所有除了 $1、$2、$3、...、$n 以外的内容”。因此这是不正确的。 - Eugene Yarmash
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接