33

I am making a bash script that will print and pass complex arguments to another external program.

./script -m root@hostname,root@hostname -o -q -- 'uptime ; uname -a'

How do I print the raw arguments as such:

-m root@hostname,root@hostname -o -q -- 'uptime ; uname -a'

Using $@ and $* removes the single quotes around uptime ; uname -a which could cause undesired results. My script does not need to parse each argument. I just need to print / log the argument string and pass them to another program exactly how they are given.

I know I can escape the quotes with something like "'uptime ; uname -a'" but I cannot guarantee the user will do that.

4

7 に答える 7

35

引用符は、引数がスクリプトに渡される前に削除されるため、保持するには遅すぎます。できることは、引数を内部コマンドに渡すときにそれらの効果を保持し、印刷用に引用/エスケープされた同等の引数のバージョンを再構築することです。

内部コマンドに引数を渡す場合"$@"-- 二重引用符を使用すると、 $@ は元の単語の区切りを保持します。これは、内部コマンドがスクリプトとまったく同じ引数リストを受け取ることを意味します。

印刷の場合、bash の printf コマンドで %q 形式を使用して、引用符を再構築できます。これは常に元の引用を再構築するとは限りませんが、同等の引用/エスケープされた文字列を構築することに注意してください。たとえば、引数を渡した場合、出力'uptime ; uname -a'されるか、その他の同等のものが表示される場合があります (同様の例については、@William Pursell の回答を参照してください)。uptime\ \;\ uname\ -a"uptime ; uname -a"

これらの使用例を次に示します。

printf "Running command:"
printf " %q" innercmd "$@" # note the space before %q -- this inserts spaces between arguments
printf "\n"
innercmd "$@"

bash バージョン 4.4 以降を使用している場合は、@Qパラメーター展開で修飾子を使用して引用符を追加できます。これは、単一引用符の使用を好む傾向があります (printf %qエスケープの好みとは対照的に)。これを と組み合わせて$*、妥当な結果を得ることができます。

echo "Running command: innercmd ${*@Q}"
innercmd "$@"

は、すべての引数を 1 つの文字列にマッシュアップし、それらの間に空白を入れます$*が、これは通常は役に立ちませんが、この場合、各引数は個別に引用符で囲まれているため、実際には (おそらく) 必要な結果が得られます。(まあ、 を変更IFSしない限り、その場合、引数間の「空白」は の最初の文字になります。これは、あなたが望むものではない$IFSかもしれません.)

于 2012-05-31T15:05:29.480 に答える
5

ユーザーがコマンドを次のように呼び出した場合:

./script 'foo'

スクリプトに与えられる最初の引数はfoo、引用符なしの文字列です。fooスクリプトがそれと、引数として取得できる他のメソッド (./script $(echo foo)または./script fooまたは または./script "foo"など)を区別する方法はありません./script \f\o""''""o

于 2012-05-31T14:57:31.767 に答える
4

ユーザーがおそらく入力したものにできるだけ近い引数リストを出力したい場合:

#!/bin/bash
chars='[ !"#$&()*,;<>?\^`{|}]'
for arg
do
    if [[ $arg == *"'"* ]]
    then
        arg=\""$arg"\"
    elif [[ $arg == *$chars* ]]
    then
        arg="'$arg'"
    fi
    allargs+=("$arg")    # ${allargs[@]} is to be used only for printing
done
printf '%s\n' "${allargs[*]}"

完璧ではありません。のような議論''\''"'は、正当化されるよりも受け入れるのが難しい.

于 2012-05-31T16:02:45.590 に答える
-2

eval "./script -m root@hostname,root@hostname -o -q -- 'uptime ; uname -a'"

https://ss64.com/bash/eval.html

于 2020-06-08T22:33:52.597 に答える