web-dev-qa-db-ja.com

シェルスクリプトの変数にコマンドを保存する方法は?

後で使用するコマンドを変数に保存したい(コマンドの出力ではなく、コマンド自体)

次のような簡単なスクリプトがあります。

command="ls";
echo "Command: $command"; #Output is: Command: ls

b=`$command`;
echo $b; #Output is: public_html REV test... (command worked successfully)

ただし、もう少し複雑なことをしようとすると失敗します。たとえば、私が作る場合

command="ls | grep -c '^'";

出力は次のとおりです。

Command: ls | grep -c '^'
ls: cannot access |: No such file or directory
ls: cannot access grep: No such file or directory
ls: cannot access '^': No such file or directory

後で使用するために、このようなコマンド(パイプ/複数のコマンド)を変数に保存する方法はありますか?

94
Benjamin

Evalを使用します。

x="ls | wc"
eval "$x"
y=$(eval "$x")
echo "$y"
128
Erik

Donotuse eval!任意のコードの実行を引き起こす大きなリスクがあります。

BashFAQ-5 -コマンドを変数に入れようとしていますが、複雑なケースは常に失敗します。

配列に入れて、二重引用符"${arr[@]}"ですべての単語を展開してnotIFSで単語を分割to 単語分割

cmdArgs=()
cmdArgs=('date' '+%H:%M:%S')

内部の配列の内容を確認します。 declare -pを使用すると、内部の配列の内容を、各コマンドパラメーターを個別のインデックスで確認できます。そのような引数の1つにスペースが含まれている場合、配列への追加中に引用符で囲むと、Word分割による分割が防止されます。

declare -p cmdArgs
declare -a cmdArgs='([0]="date" [1]="+%H:%M:%S")'

コマンドを次のように実行します

"${cmdArgs[@]}"
23:15:18

(または)bash関数を使用してコマンドを実行し、

cmd() {
   date '+%H:%M:%S'
}

そして、関数を単に

cmd

POSIX shには配列がないため、最も近い方法は、位置パラメーターの要素のリストを作成することです。 POSIX shメールプログラムを実行する方法を次に示します

# POSIX sh
# Usage: sendto subject address [address ...]
sendto() {
    subject=$1
    shift
    first=1
    for addr; do
        if [ "$first" = 1 ]; then set --; first=0; fi
        set -- "$@" --recipient="$addr"
    done
    if [ "$first" = 1 ]; then
        echo "usage: sendto subject address [address ...]"
        return 1
    fi
    MailTool --subject="$subject" "$@"
}

このアプローチは、リダイレクトのない単純なコマンドしか処理できないことに注意してください。リダイレクト、パイプライン、for/whileループ、ifステートメントなどを処理できません。

32
Inian
var=$(echo "asdf")
echo $var
# => asdf

このメソッドを使用すると、コマンドがすぐに評価され、その戻り値が保存されます。

stored_date=$(date)
echo $stored_date
# => Thu Jan 15 10:57:16 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 10:57:16 EST 2015

バックティックと同じ

stored_date=`date`
echo $stored_date
# => Thu Jan 15 11:02:19 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 11:02:19 EST 2015

$(...)でevalを使用しても、後で評価されることはありません。

stored_date=$(eval "date")
echo $stored_date
# => Thu Jan 15 11:05:30 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 11:05:30 EST 2015

evalを使用すると、evalが使用されている場合に評価されます

stored_date="date" # < storing the command itself
echo $(eval "$stored_date")
# => Thu Jan 15 11:07:05 EST 2015
# (wait a few seconds)
echo $(eval "$stored_date")
# => Thu Jan 15 11:07:16 EST 2015
#                     ^^ Time changed

上記の例で、引数を指定してコマンドを実行する必要がある場合は、保存する文字列にそれらを入れます

stored_date="date -u"
# ...

Bashスクリプトの場合、これはめったに関連しませんが、最後の注意点です。 evalに注意してください。制御する文字列のみを評価し、信頼できないユーザーからの文字列や信頼できないユーザーの入力から作成された文字列を評価しない.

  • コマンドを引用することを思い出させてくれた@CharlesDuffyに感謝します!
22
Nate