总而言之:
问题和示例可以在本地测试:
sh -c "echo 'how to print single quote here'"
细节:
我有一个这样的配置:
upload_server = ('192.168.1.1', 10051)
现在我需要一个 shell 脚本来替换服务器配置。在本地我可以使用 sed 来完成:
sed -E 's/( upload_server = ).*/\\1('\"'$a'\"', 10051)/g' config.py
但有大量的机器必须更改配置。
正确的计划是ssh
与 for..in 一起使用:
for i in `cat hosts`; do ssh $i "cmd"; done
但要更改配置还需要一个sudo
,它看起来像这样:
for i in `cat hosts`; do ssh $i "sudo -c \"cmd\""; done
现在在 sed 中:
upload_server=123.123.123.123
upload_server_port=1000
cmd="sed -E 's/( upload_server = ).*/\\1('\"\"'\"'${upload_server}'\"'\"\"', ${upload_server_port})/g' config.py"
ssh $i "sudo -c \"${cmd}\""
配置结果:
upload_server = (123.123.123.123, 1000)
应该是这样的:
upload_server = ('123.123.123.123', 1000)
现在我对引号的用法感到很困惑。:(
答案1
在这种情况下,您可以通过在标准输入上传递 sed 脚本来完全绕过引用问题。 SSH 将本地标准输入路由到远程进程,sudo 只是将其保持打开状态,而 sed 可以在 stdin 上读取其脚本。您可以使用以下命令传递标准输入的内容这里的文档。
for i in `cat hosts`; do
ssh "$i" 'sudo sed -f - …' <<'EOF'
s/( upload_server = ).*/\1("$a", 10051)/g
EOF
done
更一般地说,只要您不需要在 stdin 上传递数据,您就可以通过 SSH 在 stdin 上传递 shell 片段,而不必担心引用。
for i in `cat hosts`; do
ssh "$i" sudo sh <<'EOF'
sed 's/( upload_server = ).*/\1("$a", 10051)/g' …
EOF
done
从您的问题中不清楚您是否打算插入"$a"
配置文件,或者本地 shell 中"something"
变量的值在哪里。如果你想引用局部变量,那么使用带有插值的here文档,并在here文档中用反斜杠进行保护。请注意,由于由 sed 和第二个片段中的远程 shell 进行解析,变量的值不得包含任何字符或换行符。a
something
$\`
\/'
ssh "$i" sudo sh <<EOF
sed 's/( upload_server = ).*/\\1("$a", 10051)/g' …
EOF
答案2
$ ssh localhost sh -c \"echo \\\'how to print single quotes here\\\'\"
'how to print single quotes here'
$ ssh localhost echo \\\'how to print single quotes here\\\'
'how to print single quotes here'
要理解这些规则,请记住本地 shell 会删除一级引用,然后 SSH 会调用远程 shell,该远程 shell 会删除第二级引用。