![一个微小而简单的脚本失败,这是输出“没有这样的文件或目录”](https://linux22.com/image/56886/%E4%B8%80%E4%B8%AA%E5%BE%AE%E5%B0%8F%E8%80%8C%E7%AE%80%E5%8D%95%E7%9A%84%E8%84%9A%E6%9C%AC%E5%A4%B1%E8%B4%A5%EF%BC%8C%E8%BF%99%E6%98%AF%E8%BE%93%E5%87%BA%E2%80%9C%E6%B2%A1%E6%9C%89%E8%BF%99%E6%A0%B7%E7%9A%84%E6%96%87%E4%BB%B6%E6%88%96%E7%9B%AE%E5%BD%95%E2%80%9D.png)
脚本是:
#!/bin/bash
IFS="
"
command="ls /tmp"
for file in `$command`;
do
echo $file
done
输出是:
$ ./test.sh
./test.sh: line 17: ls /tmp: No such file or directory
答案1
问题是 bash 不会正确执行包含空格的变量,因为您已设置$IFS
为换行符。这导致它尝试将整个事情作为一个命令执行,而不是将第一个单词作为命令并将其余单词作为参数传递。
如果您要使用 运行此命令strace
,而不是看到以下内容:
execve("/bin/ls", ["ls", "/tmp"], [/* 42 vars */]) = 0
--- -----
| |-------------> 2nd argument
|---------------------> 1st argument, the command to run.
您会看到第一个参数不是ls /tmp
单独ls
的,这是系统无法执行的。
如果您不设置变量,您的脚本实际上将按您的预期工作IFS
。然而,你真的不应该使用ls
迭代命令的输出,除非你知道输出永远不会包含空格或其他奇怪的字符。为了显示:
$ touch 'file name with spaces'
$ for i in $(ls ./); do echo "$i"; done
file
name
with
spaces
正确的方法是使用其中之一:
$ for i in *; do echo "i is: $i"; done
i is: file name with spaces
$ find . -type f | while IFS= read -r i; do echo "i is: $i"; done
i is: ./file name with spaces
如果你真的非常想使用ls
,至少要用while循环来使用它。虽然这仍然会因为各种原因而中断,但至少它可以处理空格:
$ ls | while read i; do echo "i is: $i"; done
i is: file name with spaces
最后,能够应对任何文件名,包括带有换行符、反斜杠、空格或其他任何内容的文件名。使用:
$ find . -type f -print0 | while IFS= read -r -d '' i; do echo "i is: $i"; done
i is: ./file name with spaces
答案2
拆下该IFS
零件。
$IFS
是 的内部字段分隔符变量bash
。您在脚本中添加行会导致bash
仅在换行符中分隔字段,而不是在默认值(空格、制表符和换行符)中分隔字段。ls
给出以制表符分隔的输出。
这有效:
#!/bin/bash
command="ls /tmp"
for file in `$command`;
do
echo $file
done