Bashスクリプトファイルでコマンドをどのようにパラメータ化しますか?

Bashスクリプトファイルでコマンドをどのようにパラメータ化しますか?

編集 - bash$1変数を使用しません。例では、フィールド指定子を使用しています。$1$2$3入力awkレコードフィールドです。残念ながら、例をあまりにも早く見て、例が混同された。

私はこれが一般的な問題だと思います。awkプレゼンテーションツールとして使用しています。目的は、(またはすべてのツール)コマンドawkで()スクリプトパラメータを暗示することです。awk

STDINでasとして提供されたフィールドを使用してawk結果を生成します。識別子は$1STDINストリームのフィールドです$2$3awk

必須ソリューションA(優先概念)、例:…

#!/bin/bash  -f
#   script: blue.sh
#
    awk -e '{ print $1 " and " $2 " silly example" ;}'
#

そして望ましい出力:

$  echo  "red blue yellow" > ./blue.sh 
red and blue silly example
$

おそらく代替Bを考えることができます。

#!/bin/bash  -f
#   script: green.sh
#
    wrk="awk -e '{ print \$3 \" and \" \$2 \" variable example\" ;}'  "
#
    echo "work is:"
    echo $wrk
    echo
    $wrk

そして望ましい出力:

$  echo  "red blue yellow" > ./green.sh 
wrk is:
awk -e '{ print $3 " and " $2 " variable example" ;}'  

yellow and blue variable example
$

問題は-e式の参照にあります。

これらの例を実装する方法はありますか?

答え1

これはおそらく」変数に保存されたコマンドをどのように実行できますか?」と言いますが、いろいろな部分で構成されていますので、お客様の状況に合わせて具体的にお答えいたします。

  1. コマンドを変数に保存し、その変数を使用して実行します。
  2. にデータを渡しますawk

「変数で命令を実行する」ビット

以下は、スクリプトの代替実装に関する提案です。

#!/bin/bash

wrk=( awk -v a="$3" -v b="$2"
      'BEGIN { printf "%s and %s variable example\n", a, b }' )

awk -v a="$1" -v b="$2" 'BEGIN { printf "%s and %s silly example\n", a, b }'

printf 'wrk is: %s\n' "${wrk[*]}"
"${wrk[@]}"

これを実行してください:

$ ./blue.sh "red" "blue" "yellow"
red and blue silly example
wrk is: awk -v a=yellow -v b=blue BEGIN { printf "%s and %s variable example\n", a, b }
yellow and blue variable example

私がしたことはawkコマンドを保存することでした。大量に文字列ではありません。これにより、配列内の個々の要素を配列の残りの部分とは別に個別の要素として維持しながら、正しく参照できます。たとえば、先頭の単語は、awk配列(フルコード)の最後の項目とはawk別の単語です。

コマンドとして使用される場合、"${wrk[@]}"配列の各要素は別々のコマンドライン引数として使用されます(最初の要素はコマンドです)。拡張参照を使用"${wrk[@]}"すると、各要素が個別に参照されます(使用しても${wrk[@]}効果はありません)。

これは変数にコマンドを保存して実行する方法です。つまり、配列を使用し、配列要素と配列拡張を正しく参照していることを確認してください。

シェルスクリプト呼び出しの場合は、配列で単一の文字列生成をprintf使用します(デフォルトでは、すべての要素はスペースで区切られています)。これは、シェルが配列を作成するときにこれらの要素を削除するため、予想される個々の要素への参照を保持しないことを意味します(同様の操作を実行するときに引用符を削除するのと同じです)。"${wrk[*]}"wrka='hello world'

表示する個々の要素ごとに、wrk次のものを使用してくださいprintf 'element: "%s"\n' "${wrk[@]}"。これは出力されます

element: "awk"
element: "-v"
element: "a=yellow"
element: "-v"
element: "b=blue"
element: "BEGIN { printf "%s and %s variable example\n", a, b }"

この特別なケースでは、必要に応じてシェル機能を使用することもできます。

#!/bin/bash

wrk () {
    awk -v a="$1" -v b="$2" 'BEGIN { printf "%s and %s variable example\n", a, b }'
}


awk -v a="$1" -v b="$2" 'BEGIN { printf "%s and %s silly example\n", a, b }'

wrk "$3" "$2"

関数のとは、$1スクリプト$2ではなく関数の最初と2番目のパラメータを表します。

これを実行してください:

$ ./blue.sh "red" "blue" "yellow"
red and blue silly example
yellow and blue variable example

- 特定awkビット

awk コマンドラインにデータを渡すには、-v 初期化awk変数を使用しますawk。これはシェル拡張を介してコードに変数を注入するよりも優れていますawk。これは、ユーザーが単純なデータではなく実行可能なコードを注入できるようにするためです(たとえば、単に$3a;といくつかのコードを含めることによって)。awk望むより」awkのコマンドラインパラメータ「そしてこのサイトにも同様の質問がありますこれについて詳しく学んでください。

awk環境変数を使用してデータを渡すこともできます。

a=$3 b=$2 awk 'BEGIN { printf "%s and %s variable example\n", ENVIRON["a"], ENVIRON["b"] }' )

または、

export a="$3"
export b="$2"
awk 'BEGIN { printf "%s and %s variable example\n", ENVIRON["a"], ENVIRON["b"] }' )

また、標準入力には読み取り可能な入力がないため、awk単一ブロックでコードを実行しています。BEGIN

答え2

解決策を見つけましたが、結果はもともと考えていたものとはかなり異なりました。bashコマンドで-script変数を拡張する方法が見つからなかったため、これを「構成」する必要がありました。xargsこれは、シェルが目的の操作を実行する方法に関連するさまざまな理由で不適切であることがわかりました。

実行中の例を見て、次のコードを見て、何が起こるのかを説明します。 「#(2)」などのタグで議論する領域を表示しました。

はい:

入力する...

$ svn status -qu ..
M            28637   /src/line.h
M            28637   /src/line.cpp
        *    28637   /testing/CheckWindows.py

処理...

繰り返しスクリプトは2つのパラメータを使用します。

  1. 入力リストから実行するテンプレートまたは1つ以上のコマンド
  2. awk入力ストリームフィルタリングのためのいくつかのコマンド

コマンドライン:

 svn status -qu .. | repeat                                        \
                       'cp -v $ff  /mnt/testhost/testarea/r02/$ff' \
                       "{  if( $1 == "M" ){ print  $3; } }"

出力...

'/src/line.h' -> '/mnt/testhost/testarea/r02/src/line.h'
'/src/line.cpp' -> '/mnt/testhost/testarea/r02/src/line.cpp'

どうしたの?

  • ローカルで変更されたファイルのみコピーr02/testarea
    • 明らかにフィルタリングは何でもよい
  • の目的は、repeatフィルタリングされた入力リストから一連のコマンドを繰り返すことです。

コメント付きコード:

    #!/bin/bash
    #   repeat.bash

    function  repeat
    {
        local -a    actions=()
        local       DELIMITER=";"
        local       filter="${2}"
        local       cmd=""

        local       wrk="${1}${DELIMITER}"        # (1)   Template
        local       str=""


        while [[ $wrk  ]]                         # (2)   Split-up individual commands
        do
            str="${wrk%%"${DELIMITER}"*}"
            actions+=( "${str}" )

            wrk="${wrk#*"${DELIMITER}"}"
        done

        echo    "actions: "                       # (3)   Debugging code

        for action in "${actions[@]}"
        do
            echo  "        => \"${action}\"."
        done
        echo  "filter  => '${filter}'."


        ex="${filter}"                            # (4)   Awk instructions to 
                                                  #       process input stream


        for ff in $(awk -e "${ex}")               # (5)   .
        do
            for action in "${actions[@]}"         # (6)   .
            do
                cmd="${action//\$\{ff\}/${ff}}"   # (7)   .
                cmd="${cmd//\$ff/${ff}}"

                ${cmd}                            # (8)   .
            done
        done

        return

    }

    repeat  "${@:1}"                              # (9)   .

ノート:

  1. Argは$1コマンドテンプレートです。
    *
    後で解析するために末尾に区切り文字を追加します。
  2. $1通常、複数のコマンドを使用します。入力パラメータを別々のセミコロンで区切られたコマンド文字列に分割します。
  3. 確認のためにパラメータを印刷します。
  4. フィルタをex変数にロードします。
    *
    この例では、exフィルタのみに渡されます$2
  5. フィルタリングされた入力行によって生成された各文字列を繰り返します。
    *
    exawk選択/生成フィルタで実行されるコマンドになります。
  6. すべてのコマンドテンプレートを繰り返しますaction
  7. $ffコマンド文字列${ff}の拡張構文action
  8. 各ファイルに対して生成された各コマンドラインを実行します$ff
  9. スクリプトを実行するには、この関数を呼び出します。

poutの場合、パラメータをawkテンプレート文字列に直接注入できないため、これは非常に異なります。しかし、回避策はそれほど不便ではなく、神秘的な拡張機能なしでどのように機能するかを示しています。

私はこの考えが役に立つと信じています。今動作するスニペットがあるのでとても便利だと思います。

関連情報