![对 bash 中的变量感到困惑](https://linux22.com/image/1411137/%E5%AF%B9%20bash%20%E4%B8%AD%E7%9A%84%E5%8F%98%E9%87%8F%E6%84%9F%E5%88%B0%E5%9B%B0%E6%83%91.png)
我知道 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