这是一个后续问题发布在SO上。
我编写了一个名为的脚本except
,它应该打印除像这样给出的文件名/目录之外的所有文件名/目录。
$ ls
a b c d
$ rm $(except b d)
$ ls
b d
到目前为止我写的脚本看起来像这样
shopt -s extglob
shopt -s nullglob
old_ifs=$IFS
IFS='|'
matches="!($*)"
IFS=' '
printf '%s' $matches
IFS=$old_ifs
这或多或少有效,但主要问题是 printf 似乎不尊重IFS
设置为(空白)。
它只是打印它们,中间没有空格。如果我改用 echo,它就可以工作(除了添加的换行符)。但出于兼容性原因,我想使用 printf 来完成此任务。我怎样才能实现这个目标?我究竟做错了什么?
我还尝试使用%q
修饰符,但也没有产生所需的输出。
printf '%q' $matches
答案1
$ ls a b c d $ rm $(except b d) $ ls b d
这是行不通的,至少不可靠,因为"except"
无法决定 shell 在将其输出传递给命令之前如何分割(并进一步扩展)其输出rm
。
要回答您的问题, printf 不使用$IFS
.唯一使用 IFS 的命令是read
.除此之外,shell 使用 $IFS 进行分词并连接 中的位置参数"$*"
。
您可能想要:
printf '%s ' $matches
或者
printf '%s\n' $matches
但话又说回来,在
rm $(except a b)
except
解释该命令行的 shell 将根据自己的情况分割输出$IFS
(默认为空格、制表符或换行符,这就是为什么使用空格或\n
以上没有区别),并且还会扩展其中的通配符。
a
因此,如果除了和之外的文件b
是"this file.txt"
和**a**
,except
将输出"this file.txt **a** "
,并且您最终将尝试删除this
,file.txt
和a
(因为将扩展到其名称中的**a**
所有文件)。a
如果你想用空格连接匹配而不用尾随空格,你可以这样做:
IFS=
set -- $matches
IFS=' '
matches="$*"