簡體   English   中英

bash中的雙引號

[英]Double quotes inside quotes in bash

我需要將$ var_path傳遞到單引號內的bash腳本,然后在遠程主機上執行commnd。 我知道單引號不允許傳遞變量,因此嘗試了雙引號,但在sed中出錯。 假設發生這種情況是因為其模板也使用了“”。

var="Test text"
var_path="/etc/file.txt"
echo "$var"|ssh root@$host 'cat - > /tmp/test.tmp && sed -n "/]/{:a;n;/}/b;p;ba}" $var_path > /tmp/new.conf.tmp'

所以用“”

var="Test text"
    var_path="/etc/file.txt"
    echo "$var"|ssh root@$host "cat - > /tmp/test.tmp && sed -n "/]/{:a;n;/}/b;p;ba}" $var_path > /tmp/new.conf.tmp"

sed錯誤

sed: -e expression #1, char 0: unmatched `{'
./script.sh: line 4: n: command not found
./script.sh: line 4: /}/b: No such file or directory
./script.sh: line 4: p: command not found

如果直接使用$ var_path而不進行替換,腳本將按預期工作。

解析為要發送到SSH中遠程系統命令的一部分的參數,將其與空格連接,然后傳遞至遠程shell(類似於"${SHELL:-sh}" -c "$*" ) 。 幸運的是, 如果您的遠程SHELL是bash,bash具有內置的printf %q操作(擴展名,因此在所有其他POSIX shell中不可用)可以使字符串為eval安全,從而為ssh安全。 有關使用Python的shlex模塊在非bash shell中安全生成命令的變通方法, shlex答案的結尾。

因此,如果您有在本地工作的命令,則第一步是將其放入數組(注意"$var_path"擴展的引號,這對於進行明確的分組是必需的):

cmd=( sed -n '/]/{:a;n;/}/b;p;ba}' "$var_path" )

...您可以在本地運行以測試:

"${cmd[@]}"

...或轉換為eval-safe字符串:

printf -v cmd_str '%q ' "${cmd[@]}"

...然后使用ssh在本地運行...

ssh remote_host "$cmd_str"

...或使用eval在本地進行測試:

eval "$cmd_str"

現在,您的特定用例有一些例外-需要將其用作文字命令將其引號或轉義,但如果您希望它們保留其特殊含義, 則不能將其引號。 &&| >是示例。 幸運的是,您可以自己構建字符串的那些部分來解決此問題:

ssh remote_host "cat - >/tmp/test.tmp && $cmd_str >/tmp/new.conf.tmp"

...相當於本地數組擴展...

cat - >/tmp/test.tmp && "${cmd[@]}" >/tmp/new.conf.tmp

或當地評估

eval "cat - >/tmp/test.tmp && $cmd_str >/tmp/new.conf.tmp"

附錄:支持非Bash遠程Shell

一個警告: printf %q保證以bash (或ksh,如果您在本地ksh中使用printf %q話)來引用事物,將它們評估為與輸入完全匹配。 如果您的目標系統的外殼不支持$'' POSIX擴展,則此保證將不再可用,並且面對所有可能的輸入時,必須采用更有趣的技術來保證魯棒性。

幸運的是,Python標准庫包含一個函數,用於轉義任何符合POSIX的外殼程序的任意字符串:

quote_string() {
  python -c '
import sys
try:
  from pipes import quote  # Python 2
except ImportError:
  from shlex import quote  # Python 3

print(" ".join([quote(x) for x in sys.argv[1:]]))
' "$@"
}

此后,當您需要一個等效於printf '%q ' "$@" ,即使遠程shell不是bash也可以使用的等效項時,可以運行:

cmd_str=$(quote_string "${cmd[@]}")

一旦使用雙引號,嵌入式命令就可以簡單地使用單引號。 之所以有效,是因為雙引號變量替換將嵌入式單引號視為常規字符...沒什么特別的。

var="Test text"
    var_path="/etc/file.txt";
    echo "$var"|ssh root@$host "cat - > /tmp/test.tmp && sed -n '/]/{:a;n;/}/b;p;ba}' $var_path > /tmp/new.conf.tmp"

如果要在雙引號內分配和使用變量,則將更加棘手。

root @ anywhere很危險...沒有其他方法嗎? 如果您使用證書,希望它們將root限制為特定命令。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM