一个微小而简单的脚本失败,这是输出“没有这样的文件或目录”

一个微小而简单的脚本失败,这是输出“没有这样的文件或目录”

脚本是:

#!/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

相关内容