web-dev-qa-db-ja.com

コマンドラインでのコマンド置換を防ぐ方法は?

テキストを別のプログラムへの入力として書き込む場合、目的のテキスト内の二重引用符で囲まれたコマンド置換は、シェルによって解釈および展開されることがわかりました

回答内のリンク here は、単一引用符を使用してパラメーターの展開やコマンドの置換を防止できることを示しています。ただし、コマンド置換を単一引用符で囲むと、シェルがコマンド置換を拡張するのを停止できないことがわかりました

実行するコマンドではなくテキストとして意図されているコマンド置換をシェルが解釈しないようにするにはどうすればよいですか?

デモ

$ echo "`wc -l *`"

現在のディレクトリのすべてのファイルの行を数えようとします

$ echo "'`wc -l *`'"

同じ結果、つまり現在のディレクトリ内のすべてのファイルの行をカウントします

updateこのデモンストレーションから、問題は単一引用符を引用していることにあるようだと気づきました。単一引用符と`(バックティック)を二重引用符で囲むと思います リテラルの意味は保持されます (つまり、抑制)シングルクォートはリテラルの意味を保持しません(つまり、バックティック)コマンド置換を紹介します。

私の使用例では、別のコマンドの入力を引用符で囲む必要があります。これで document と言って:

単一引用符は単一引用符内には使用できません

単一引用符で囲まれたコマンド置換が(二重)引用符で囲まれた文字列内にあるときに、単一引用符で囲まれたコマンド置換が展開されないようにするにはどうすればよいですか?バックスラッシュエスケープを使用する以外にそれを行う方法があるはずです

実際の状況

プログラムで、タスクの説明を別々の行に分割する唯一の方法を使用しているのは、説明を二重引用符で囲むことです。

$ task add "first line doesn\'t say much
Second line says a lot but part of this line does not appear in the resulting description 'truncate -s0 !(temp_file | temp_dir)' truncates all files to 0 bytes as shown by: '`wc -l *`'"

結果の説明:

first line doesn\ -s0 !(temp_file | temp_dir)' truncates all files to 0 bytes as shown by: 0 file1 10 file2 0 directory1 0 directory2 502 file3 123 file4 162 file5 0 directory3

ご覧のように

't say much
Second line says a lot but part of this line does not appear in the resulting description 'truncate

説明から欠落しており、シェルは'wc -l *'をコマンド置換として解釈したため、現在のディレクトリ内のすべてのファイルの行数が説明の一部として含まれています

シェルがtaskへの引数の\(バックスラッシュ)と-sの間の部分を削除する原因、およびシェルが上記の単一引用符で囲まれたコマンド置換を解釈しないようにする方法(つまり、'`wc -l *`')?

2
MyWrathAcademia

ここ(改行を追加)、

$ task add "first line doesn\'t say much
Second line says a lot but part of this line does not appear in the
resulting description 'truncate -s0 !(temp_file | temp_dir)' truncates
all files to 0 bytes as shown by: '`wc -l *`'"

文字列全体が二重引用符で囲まれているため、コマンド置換やその他の展開がそこで実行されます。これは、シェルでtaskがその文字列を見る前に発生します。バックスラッシュでそれを防ぐか、その部分を一重引用符で囲む必要があります。

例えば。

$ printf "%s\n" "...shown by: '\`wc -l *\`'"
...shown by: '`wc -l *`'

そう、

task add "...shown by: '\`wc -l *\`'"

文字列...shown by: '`wc -l *`'taskに渡します。それで何をするかはそれ次第です。

バックスラッシュを使用したくない場合は、単一引用符で囲む方法は次のとおりです。

#               aaaaaaaaaaaaaaaaBBBBBBBBBBBaaa
$ printf "%s\n" "...shown by: '"'`wc -l *`'"'"
...shown by: '`wc -l *`'

aは二重引用符で囲まれた部分を示し、Bは単一引用符で囲まれた部分です。これらはシェルコマンドラインで連結されるだけです。リテラル単一引用符は二重引用符で囲まれた文字列内にあります。 )


単一引用符とバックスラッシュについては、二重引用符内で単一引用符をエスケープする必要はありません。実際、バックスラッシュはそこに残ります。

$ printf "%s\n" "foo'bar"
foo'bar
$ printf "%s\n" "foo\'bar"
foo\'bar

あなたが示すものから、taskは少なくとも最初の単一引用符で囲まれた文字列を引数から削除しているようです(削除された部分は't say much ... 'truncateだったので、その後にWordが追加されます)

Shellnotを実行します。これは正常に機能します。

$ printf "%s\n" "a 'quoted string' to test"
a 'quoted string' to test

シェルが\(バックスラッシュ)と-sの間のtaskへの引数の一部を削除する原因

シェルがそうしているのではない可能性が高いです。

また、シェルが上記の単一引用符で囲まれたコマンド置換(つまり、'`wc -l *`')を解釈しないようにするにはどうすればよいですか。

一重引用符ではなく、二重引用符で囲まれ、その横に一重引用符が付いています。

2
ilkkachu

一重引用符の強力な引用を使用します。

printf '%s\n' '`wc -l *`'

また、printfに渡す引数に単一引用符も含める場合は、次のように'自体に別の引用符を使用する必要があります。

printf '%s\n' '`wc -l *` and a '"'"' character'

または:

printf '%s\n' '`wc -l *` and a '\'' character'

その他の代替手段として、二重引用符内にバックスラッシュを付けて`をエスケープする方法があります。

printf '%s\n' "\`wc -l *\` and a ' character"

または、`をいくつかの拡張の結果にする:

backtick='`'
printf '%s\n' "${backtick}wc -l *${backtick} and a ' character"

また注意してください:

cat << 'EOF'
`wc -l *` and a ' character and a " character
EOF

引用を気にすることなく任意のテキストを出力するには(最初のEOFの前後の引用符に注意してください)。

次のこともできます:

var=$(cat << 'EOF'
echo '`wc -l *`'
EOF
)

ksh93またはmkshを使用すると、次のように最適化できます。

var=$(<<'EOF'
echo '`wc -l *`'
EOF
)

zshでも機能しますが、サブシェルでcatを実行します)$varに文字どおりecho '`wc -l *`'を含めます。

fishシェルでは、'内に'...'\'で埋め込むことができます。

printf '%s\n' '`wc -l *` and a \' character'

とにかく`は特別ではないので、

printf '%s\n' "`wc -l *` and a ' character"

同様に動作します。

Rc、es、またはzsh -o rcquotesでは、'内に'...'''とともに挿入できます。

printf '%s\n' '`wc -l *` and a '' character'

詳細については、 特殊文字を通常の文字として使用する方法 を参照してください。

11

以下に示すように、バックスラッシュを使用してバックティックをエスケープできます。

echo "\`wc -l *\`"
1
user138278

any任意の文字シーケンスをエスケープして、特殊文字が処理されず、置換が行われないようにするには:

  1. すべての''\''に置き換えます
  2. 結果の文字列を一重引用符で囲みます。

例えば:

`wc -l 'my file.txt'`

なる

'`wc -l '\''my file.txt'\''`'

文字列が'で開始または終了する場合、開始/終了時に''で終了することに注意してください。これは何もせず、削除できますが、そこに残すことは有効です(たとえば、文字列を保持するために-エスケープ機能は簡単です)。

0
Keiji