bash 中的 sudo echo 仅适用于双引号,但不适用于单引号
sudo echo in bash only work with double quote, but not single quote
我有 2 个变量 PASSWORD="123" 和 FILEPATH="/dir-1/dir2",它们都导出为对所有用户可见的环境变量。
我正在尝试回显到文件 /dir-1/dir2/file,该文件属于 root 作为 user1。
我知道这个问题是因为 shell 重定向不适用于 sudo,即 sudo echo <TEXT> >> <FILE>
,所以我所做的是:
sudo bash -c 'echo "MY.Password $PASSWORD" >> ${FILEPATH}/file'
sudo bash -c 'echo MY.Password $PASSWORD >> ${FILEPATH}/file'
我原以为文件的最后一行是:
MY.Password 123
但是,尽管变量被正确替换,MY.Password 123
的预期内容并没有出现在 /dir-1/dir2/file
文件的最后一行。
然后我尝试了
sudo bash -c "echo My.Password '$PASSWORD' >> ${FILEPATH}/file"
sudo bash -c "echo My.Password $PASSWORD >> ${FILEPATH}/file"
两者都有效。
然后我开始想是不是因为单引号的缘故,我尝试用双引号将单引号转义:
sudo bash -c 'echo "'"MY.Password $PASSWORD"'" >> "'"${FILEPATH}"'"/file'
这个看起来很奇怪的命令也有效...
谁能解释为什么我的命令不起作用,为什么最后一个看起来很奇怪的命令起作用了?
sudo
默认情况下不会通过您的环境。 sudo
有一个选项 -E
或 --preserve-env
可以在 sudo
下保留命令 运行 中的现有环境。示例:
# let's set some variable `a`
a=Hello
# will print an empty line
sudo sh -c 'echo $a'
# will print Hello
sudo sh -c "echo $a"
# will print an empty line
sudo -E sh -c 'echo $a'
# because first we need to make `a` exported
export a
# this will print Hello
sudo -E sh -c 'echo $a'
当您使用双引号时,扩展发生在调用 sudo
之前。所以 expansion/execution 是这样的:
$ sudo sh -c "echo $a"
+ sudo sh -c 'echo Hello'
+ sh -c 'echo Hello'
+ echo Hello
Hello
当您使用单引号时,expansion/execution 如下所示:
$ sudo sh -c 'echo $a'
+ sh -c 'echo $a'
+ echo $a
# now it depends if `$a` exists here, after `sudo` inside `sh`
+ echo
如果变量不在环境中,它将展开为空。
sudo bash -c 'echo "MY.Password $PASSWORD" >> ${FILEPATH}/file'
PASSWORD
和 FILEPATH
变量未在 sudo
中设置,因此它们扩展为空字符串。
sudo bash -c "echo My.Password '$PASSWORD' >> ${FILEPATH}/file"
首先在您的 shell 中扩展了 PASSWORD
和 FILEPATH
变量。然后执行sudo
,然后执行bash
。在 bash
中执行 echo My.Password 'PASSWORD' >> FILEPATH/file
所以它可以工作。
sudo bash -c 'echo "'"MY.Password $PASSWORD"'" >> "'"${FILEPATH}"'"/file'
让我们用换行符拆分它:
sudo bash -c 'echo "'\
"MY.Password $PASSWORD"\
'" >> "'\
"${FILEPATH}"\
'"/file'
因为您的变量在 "
中,所以它们在调用 sudo 之前被展开。然后在 sudo
内,它们已经展开并且值被正确引用,值在子 shell 的 "
内。这是 "most" 的正确形式,因为在 "
中应该正确引用扩展值,这样当 ex. FILEPATH
里面有一个space。
我通常这样做:
sudo bash -c 'echo MY.Password "" >> ""/file' -- "$PASSWORD" "$FILEPATH"
这让我不用担心在 shell 中使用 "
引号,并且仍然在不改变环境的情况下将正确引用的变量传递给 shell。
或者,您可以这样做:
export PASSWORD FILEPATH
sudo -E bash -c 'echo MY.Password "$PASSWORD" >> "$FILEPATH"/file'
或者去喝杯茶:
echo MY.Password "$PASSWORD" | sudo tee -a "$FILEPATH"/file
我有 2 个变量 PASSWORD="123" 和 FILEPATH="/dir-1/dir2",它们都导出为对所有用户可见的环境变量。
我正在尝试回显到文件 /dir-1/dir2/file,该文件属于 root 作为 user1。
我知道这个问题是因为 shell 重定向不适用于 sudo,即 sudo echo <TEXT> >> <FILE>
,所以我所做的是:
sudo bash -c 'echo "MY.Password $PASSWORD" >> ${FILEPATH}/file'
sudo bash -c 'echo MY.Password $PASSWORD >> ${FILEPATH}/file'
我原以为文件的最后一行是:
MY.Password 123
但是,尽管变量被正确替换,MY.Password 123
的预期内容并没有出现在 /dir-1/dir2/file
文件的最后一行。
然后我尝试了
sudo bash -c "echo My.Password '$PASSWORD' >> ${FILEPATH}/file"
sudo bash -c "echo My.Password $PASSWORD >> ${FILEPATH}/file"
两者都有效。
然后我开始想是不是因为单引号的缘故,我尝试用双引号将单引号转义:
sudo bash -c 'echo "'"MY.Password $PASSWORD"'" >> "'"${FILEPATH}"'"/file'
这个看起来很奇怪的命令也有效...
谁能解释为什么我的命令不起作用,为什么最后一个看起来很奇怪的命令起作用了?
sudo
默认情况下不会通过您的环境。 sudo
有一个选项 -E
或 --preserve-env
可以在 sudo
下保留命令 运行 中的现有环境。示例:
# let's set some variable `a`
a=Hello
# will print an empty line
sudo sh -c 'echo $a'
# will print Hello
sudo sh -c "echo $a"
# will print an empty line
sudo -E sh -c 'echo $a'
# because first we need to make `a` exported
export a
# this will print Hello
sudo -E sh -c 'echo $a'
当您使用双引号时,扩展发生在调用 sudo
之前。所以 expansion/execution 是这样的:
$ sudo sh -c "echo $a"
+ sudo sh -c 'echo Hello'
+ sh -c 'echo Hello'
+ echo Hello
Hello
当您使用单引号时,expansion/execution 如下所示:
$ sudo sh -c 'echo $a'
+ sh -c 'echo $a'
+ echo $a
# now it depends if `$a` exists here, after `sudo` inside `sh`
+ echo
如果变量不在环境中,它将展开为空。
sudo bash -c 'echo "MY.Password $PASSWORD" >> ${FILEPATH}/file'
PASSWORD
和 FILEPATH
变量未在 sudo
中设置,因此它们扩展为空字符串。
sudo bash -c "echo My.Password '$PASSWORD' >> ${FILEPATH}/file"
首先在您的 shell 中扩展了 PASSWORD
和 FILEPATH
变量。然后执行sudo
,然后执行bash
。在 bash
中执行 echo My.Password 'PASSWORD' >> FILEPATH/file
所以它可以工作。
sudo bash -c 'echo "'"MY.Password $PASSWORD"'" >> "'"${FILEPATH}"'"/file'
让我们用换行符拆分它:
sudo bash -c 'echo "'\
"MY.Password $PASSWORD"\
'" >> "'\
"${FILEPATH}"\
'"/file'
因为您的变量在 "
中,所以它们在调用 sudo 之前被展开。然后在 sudo
内,它们已经展开并且值被正确引用,值在子 shell 的 "
内。这是 "most" 的正确形式,因为在 "
中应该正确引用扩展值,这样当 ex. FILEPATH
里面有一个space。
我通常这样做:
sudo bash -c 'echo MY.Password "" >> ""/file' -- "$PASSWORD" "$FILEPATH"
这让我不用担心在 shell 中使用 "
引号,并且仍然在不改变环境的情况下将正确引用的变量传递给 shell。
或者,您可以这样做:
export PASSWORD FILEPATH
sudo -E bash -c 'echo MY.Password "$PASSWORD" >> "$FILEPATH"/file'
或者去喝杯茶:
echo MY.Password "$PASSWORD" | sudo tee -a "$FILEPATH"/file