![为什么 printf 在打印脚本结果时忽略 IFS?](https://linux22.com/image/28823/%E4%B8%BA%E4%BB%80%E4%B9%88%20printf%20%E5%9C%A8%E6%89%93%E5%8D%B0%E8%84%9A%E6%9C%AC%E7%BB%93%E6%9E%9C%E6%97%B6%E5%BF%BD%E7%95%A5%20IFS%EF%BC%9F.png)
这是一个后续问题发布在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="$*"