5

我不明白这行shell脚本。while 语句不需要设置 $ 的 'test' 或 [ ] 或 [[ ]] 表达式吗?为 1 还是 0?如何

while IFS= read -r -d $'\0'; do ...; done

去做?非常感谢您理解此处的语法的任何帮助。

4

4 回答 4

13

在 Bash 中,运行命令并将环境变量设置为(以及所有其他正常继承的环境变量)。因此,在将环境变量设置为空字符串(意味着没有字段分隔符)的情况下运行命令。varname=value commandvarnamevalueIFS= read -r -d $'\0'read -r -d $'\0'IFS

由于只要它成功读取输入并且没有遇到文件结尾就read返回成功(即设置$?为),因此总体效果是循环一组 NUL 分隔的记录(保存在变量中)。0REPLY

while 语句不需要设置 $ 的 'test' 或 [ ] 或 [[ ]] 表达式吗?为 1 还是 0?

testand [ ... ]and[[ ... ]]实际上不是表达式,而是命令。在 Bash 中,每个命令都返回成功(设置$?0)或失败(设置$?为非零值,通常是1)。

(顺便说一下,正如上面评论中的nosid 所指出的那样,-d $'\0'相当于.Bash-d ''变量在内部表示为 C 样式/NUL 终止的字符串,因此您不能真正在字符串中包含 NUL;例如,echo $'a\0b'只打印a. )

于 2013-08-13T19:53:50.323 回答
4

我不明白这行shell脚本。while 语句不需要设置 $ 的 'test' 或 [ ] 或 [[ ]] 表达式吗?为 1 还是 0?[声明]如何做到这一点?

每个人都在回答关于-dandIFS=参数的问题,但没有人回答你关于testand的问题[[..]]

所有标准 Unix 命令将在成功时返回零值,在退出时返回非零值。whileand语句使用该if值来确定是否继续循环:

假设您执行以下操作:

$ touch foo.txt   #Create a "foo.txt" file
$ ls foo.txt
foo.txt
$ echo $?
0
$

请注意,该ls命令在退出时返回零。现在试试这个:

$ rm foo.txt
$ ls foo.txt
ls: foo.txt: No such file or directory
$ echo $?
1
$

如果foo.txt不存在,则该ls命令在退出时返回 1。

ifand命令对此while进行操作。

进入另一个终端窗口并创建一个foo.txt文件。然后回到原来的窗口试试这个:

$ while ls foo.txt > /dev/null
> do
> echo "The file foo.txt exists"
> sleep 2
> done
The file foo.txt exists
The file foo.txt exists
The file foo.txt exists
...

每两秒钟,while 将循环检查是否存在foo.txt并打印出该语句。现在,返回第二个终端窗口并删除foo.txt. 如果您返回第一个终端窗口,您会看到while循环结束。

您可以对以下内容执行相同操作if

$ if ls foo.txt > /dev/null
> then
>     echo "foo.txt exists"
> else
>     echo "Whoops, it's gone!"
> fi

if语句将打印foo.txt 存在哎呀,它不见了!取决于目录中是否foo.txt存在名为的文件。

请注意ifwhile处理命令的返回退出值。根本不需要测试。

那么为什么要使用test,[...][[...]]语法呢?

假设您想知道是否$foo等于$bar。这就是test发挥作用的地方。试试这个:

$ foo=42
$ bar=42
$ test "$foo" -eq "$bar"
$ echo $?
0
$ bar=0
$ test "$foo" -eq "$bar"
$ echo $?
1

test 命令所做的只是在真实测试中返回零,在错误测试中返回非零值。这允许您在和语句中使用test命令。ifwhile

$ if test $foo -eq $bar
> then
>     echo "foo is equal to bar"
> else
>     echo "foo and bar are different"
> fi
foo and bar are different
$

那是什么[...]

$ ls -il /bin/test /bin/[
10958 -rwxr-xr-x  2 root  wheel  18576 May 28 22:27 /bin/[
10958 -rwxr-xr-x  2 root  wheel  18576 May 28 22:27 /bin/test

第一列是inode。如果两个文件具有相同的inode,则它们是硬链接并引用同一个文件。请注意,它们在我的系统上都是 18,576 字节。

[只是执行test命令本身的另一种方式。这两行是相同的:

if test $foo -eq $bar
if [ $foo -eq $bar ]

创建它[是为了使 shell 脚本看起来更好一些。但是,在下面,它正在运行一个命令,该命令将返回一个可以使用的零test或非零值。ifwhile

顺便说一句,在 Kornshell 和 BASH 中,[test内置在 shell 中。但是,它们确实引用了相同的内置命令。

[[...]]是首次出现在 Kornshell 中的测试的特殊版本。它允许使用模式匹配,并且速度更快,因为它不会产生另一个进程来运行test命令。

于 2013-08-13T20:28:48.807 回答
2

代码说明:

  • IFS=将 IFS 设置为 null(输入字段分隔符)
  • read使用以下选项读取当前行的命令:
  • -r: 不允许反斜杠转义任何字符
  • -d继续直到读取 DELIM 的第一个字符,而不是换行
  • $'\0'零字节(ASCII NUL 字符)

help read
于 2013-08-13T19:54:59.277 回答
2

不,test命令和[[ ...]]表达式只是提供退出状态(唯一while关心的事情)的构造,它反映了它包含的条件表达式的真实性。

例如,如果值为,则退出状态[[ $foo = bar ]]为 0(成功),否则为非零存在状态(具体为 1)。$foobar

while只要while关键字后面的命令的退出状态为 0,循环就会执行其主体。在此代码中,只要read它可以从其输入中读取某些内容,则退出状态为 0。

于 2013-08-13T19:55:02.243 回答