forループ範囲のワイルドカード拡張の問題

forループ範囲のワイルドカード拡張の問題

私が作成したbashスクリプトに問題があります。 forループ内ですべてのパラメータを繰り返して、後で「eval」コマンドに入力する文字列変数を設定します。

    for arg in "$*"
    do
        if [ $arg != $lastArg ]; then
            findTarget+="-name $arg -o "
        else
            findTarget=$(echo $findTarget | sed 's/-o$//')
            break
        fi
    done

問題は「$ *」で発生します。たとえば、パラメータに「* .c」と入力し、現在のフォルダにそのパターンと一致するファイルが含まれている場合、パラメータはそのファイル*.cに展開されます。私はこれをしたくありません。findTargetと接続しようとして-name *.c -oいます。 evalを使用し、引用符なしでは効果がないようです。これを行う方法を知っていますか(可能であれば簡単に)?注:パラメーターの総数は異なる場合があります。

以下は、スクリプトを実行する方法の例です。

$ trouver.bash *.c *.f90 someString

私のforループが終わったら、変数はfindTarget次のようになります。-name *.c -o -name *.f90

*.c*.f90現在のフォルダ内のファイルと一致する場合、または一致する場合は効果がありません。

答え1

位置パラメータを繰り返す構文はfor arg do別々です。"$*"は最初の文字と位置引数を連結したものなので、1つの$IFS要素だけを繰り返すことになります。

また、コマンドのパラメータリストを作成するには、find文字列ではなく配列が必要です。そして変数を引用することを忘れないでください!

だから:

findTarget=()
or=()
for arg
do
    [ "$arg" = "$lastArg" ] && break
    findTarget+=("${or[@]}" -name "$arg")
    or=(-o)
done

find . \( "${findTarget[@]}" \)

スクリプトを呼び出すときに必要なことに注意してください。引用する...mode*.cそれ以外の場合は、スクリプトに渡される前にシェルによって拡張されます。

trouver.bash '*.c' '*.f90' someString

対話型シェルがある場合は、zshワイルドカードを無効にしてコマンドのエイリアスを定義できます。

alias trouver.bash='noglob trouver.bash'

このようにして、次のことができます。

trouver.bash *.c *.f90 someString

この球体を拡張するシェルはありません*.c *.f90

答え2

"$*"すべてのパラメータを1つの長いパラメータにリンクするには、メソッドを使用します。これを次に変更すると、引数のリストが表示され"$@"ます。ただし、実際にfor arg in "$@"正しいイディオムを使用する必要はありませんfor arg

-oその後、新しいパラメータごとに1つを追加して使用できます${findTarget[@]+"-o "}
値が割り当てられていない場合はnullになり、値が割り当てられている場合はfindTarget通常の文字列になります。最初のループ実行ではnullに縮小され、次のループではnullになります。-ofindTarget-o

(( $# < 1 )) && echo "please provide some argument(s)" && exit 1

unset  findTarget
for    arg
do     [[ "$arg" == "$lastArg" ]] && break
       findTarget+=("${findTarget[@]+"-o "}-name $arg")
done

find . \( "${findTarget[@]}" \)

次のようにスクリプトを実行する必要があります。

$ trouver.bash '*.c' '*.f90' someString

必要に応じて、各引数はシェルによって拡張されません(二重引用符を使用してください。二重引用符は機能できますが、拡張なしで引数を保持する意図を明確に表すわけではありません)。

「一重引用符」なしでスクリプトを使用する必要がある場合は、「パス名拡張」(set -f)を削除して拡張を防ぐことができます*

$ ( set -f; trouver.bash *.c *.f90 someString )

これにより、()noglobへの変更が現在実行中のシェルに影響を与えるのを防ぎます。

これは、スクリプトが結果を作成しstdoutてサブシェル内で印刷することもできるために機能します(…)

関連情報