web-dev-qa-db-ja.com

bash / ash関数に渡された引数はどうなりますか?

- に関するこの回答は、POSIXシェルでの--の使用に関する多くの優れた情報を提供します スクリプトへのすべての引数の受け渡しに関するこの回答 次の関数につながりました:

my_echo()
{
    set -x
    echo $@ " " \"$@\"
    echo `ps | grep -- "$@" | grep -v grep | awk '{ print $1 }'` 2>/dev/null
    set +x
}

my_echo logread -f

私はOpenWRT用にこのスクリプトを書いています。灰からの出力は示しています

+ echo logread -f   "logread -f"
logread -f   "logread -f"
+ ps
+ grep -v grep
+ awk { print $1 }
+ grep -- logread -f
grep: -f: No such file or directory
+ echo

+ set +x

ええと... grepコマンドに追加した引用符はなくなりました(logread -fは引用符で囲まれていません)。

この関数をbashで試しました

+ echo logread -f ' ' '"logread' '-f"'
logread -f   "logread -f"
++ ps
++ grep --color=auto -- logread -f
++ grep --color=auto -v grep
++ awk '{ print $1 }'
grep: -f: No such file or directory
+ echo

+ set +x

興味深い...多分私の議論は別々に解析されていますか?この理論をテストするために、私は次のことを試みました。

my_echo "logread -f"

Bash出力:

+ echo logread -f ' ' '"logread' '-f"'
logread -f   "logread -f"
++ ps
++ grep --color=auto -- 'logread -f'
++ grep --color=auto -v grep
++ awk '{ print $1 }'
+ echo

+ set +x

Echoコマンドの出力は変更されませんでした(setバージョンまたは実際の出力ですが、logread -fは二重引用符で囲まれているように見えます。だから...誤解してラッキーになりましたsetによるコマンドの翻訳ですが、関数は機能するようになりました。

アッシュ出力:

+ echo logread -f   "logread -f"
logread -f   "logread -f"
+ ps
+ grep -v grep
+ awk { print $1 }
+ grep -- logread -f
+ echo

+ set +x

そして今、私は私が期待したものを手に入れています。二重引用符で囲まれた引数(単一引数)を使用してmy_echoを実行することは、次のようになります。

my_echo_new()
{
    echo `ps | grep -- "$1" | grep -v grep | awk '{ print $1 }'` 2>/dev/null
}

my_echo_new "logread -f"

だから...問題は複数の引数を扱うことにあるようです。ここで何が起こっているのですか?これは `の結果ですか、それとも関数呼び出しの結果ですか、それとも他の何かですか?両方の場所で二重引用符が必要なのはなぜですか?

1
MrMas

"$@"は、引用符で囲まれた文字列のlistに展開されます。 2つの引数logread-fを関数に渡すと、"$@"two文字列に展開されます。

したがって、grep -- "$@"を実行するとgrep -- logread -fに展開されます。これは、「-fというファイル内のlogreadのgrep」を意味します。

単一の文字列ではなく個別の引数を渡したい場合は、"$*"を使用して引数を単一の引用符で囲まれた文字列に展開します。

grep -e "$*"

grep -e "logread -f"に展開されます。 $IFSを使用する場合、位置パラメーターは"$*"の最初の文字で区切られます(デフォルトでは、これはスペースです)。また、$*または$@引用符なしのいずれかを使用しても意味がないことに注意してください。

余談ですが、私はおそらくここでpgrep/pkillを使用することを選択します。

if ! pgrep -xf "$*" >/dev/null; then
    printf 'No process matches "%s" exactly\n' "$*"
fi
3
Kusalananda