对 bash 中的变量感到困惑

对 bash 中的变量感到困惑

我知道 bash 中的变量没有类型,但对它们所分配的值感到困惑。

以下简单脚本在 bash 中运行良好

#!/bin/bash 
tail -n +2 /cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile.txt > \
/cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile2.txt

然而,以下内容并不

#!/bin/bash
tmpdir=/cygdrive/c/workdir\ \(newco\,\ LLC\)
tail -n +2 $tmpdir/workfile.txt > $tmpdir/workfile2.txt

这种行为该如何解释呢?

答案1

您应该确保用引号括住可能包含空格的变量。在您的例子中,tail正在接收三个文件:/cygdrive/c/workdir(newco,并且LLC)因为$tmpdir有三个单词以空格分隔。

我知道您在分配时避开了空格$tmpdir,但这只是为了避免在分配期间将每个单词解释为单独的命令。如果您然后echo $tmpdir,您将得到
/cygdrive/c/workdir (newco, LLC),并且那是传递给的内容tail

为了避免这种情况,请引用$tmpdir

tail -n +2 "${tmpdir}/workfile.txt" > "${tmpdir}/workfile2.txt"

答案2

在 bash 中输入第一行,然后回显该变量,您将看到以下内容:

$ tmpdir=/cygdrive/c/workdir\ \(newco\,\ LLC\)
$ echo $tmpdir
/cygdrive/c/workdir (newco, LLC)

如果还不清楚罪魁祸首是什么,请echo在第二行的开头添加并用双引号括起来。您将看到实际执行的命令:

$ echo "tail -n +2 $tmpdir/workfile.txt > $tmpdir/workfile2.txt"
tail -n +2 /cygdrive/c/workdir (newco, LLC)/workfile.txt > /cygdrive/c/workdir (newco, LLC)/workfile2.txt

您已正确转义变量赋值,但这还不够。Bash 执行简单的子字符串替换,从而插入额外的空格并破坏您的命令。

正如 @savanto 在他的回答中所建议的那样,你可以用双引号括住变量,以确保多余的空格不会被视为参数分隔符。此行:

tail -n +2 "${tmpdir}/workfile.txt" > "${tmpdir}/workfile2.txt"

变量替换后将如下所示:

tail -n +2 "/cygdrive/c/workdir (newco, LLC)/workfile.txt" > "/cygdrive/c/workdir (newco, LLC)/workfile2.txt"

这是解决该问题最常见和首选的方法。如果您迫切希望避免使用双引号,可以尝试双重转义:首先在赋值时,然后在替换后。

$ tmpdir=/cygdrive/c/workdir\\\ \\\(newco\\\,\\\ LLC\\\)
$ echo $tmpdir
/cygdrive/c/workdir\ \(newco\,\ LLC\)

三重反斜杠的快速解释:反斜杠的意思是:“将下一个字符视为常规字符,忽略任何特殊含义”(即逃避它)。第一个反斜杠是转义字符,因此第二个反斜杠将被视为反斜杠字符,而不是转义字符。因此,双反斜杠会产生单反斜杠。第三个反斜杠只是转义后面的字符,如空格或括号。例如a\\\ b将变成a\ b

现在,如果我们替换命令中的变量,它将被正确转义:

tail -n +2 /cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile.txt > /cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile2.txt

相关内容