Bashで外部コマンドの可変長引数行を作成する正しい方法

Bashで外部コマンドの可変長引数行を作成する正しい方法

私のスクリプト入力に基づいてさまざまなファイルセットを見つけるには、Bash関数で "find"コマンドを使用する必要があります。

だから私は次のようなものを持っています:

DAYS=30
case $1 in
A1) ARGLINE="-name 'FOO*.xml' -or -name 'BAR*.xml' -or -name 'BTT*.txt'"
    ;;
A2) ARGLINE="-name 'PO*xml' -or -name 'PR*xml'"
    ;;
...
esac
find . -maxdepth 1 -type f -mtime +${DAYS} `${ARGLINE}`

これはうまくいきます。

しかし、次のように変数を使用して日数を検索したいと思います。

DAYS=30
case $1 in
A1) ARGLINE="-name 'FOO*.xml' -or -name 'BAR*.xml' -or -name 'BTT*.txt'"
    ;;
A2) ARGLINE="-name 'PO*xml' -or -name 'PR*xml'"
    ;;
...
esac
if [[ $# -gt 1 ]]; then
    DAYS=$2
fi
find . -maxdepth 1 -type f -mtime +${DAYS} `${ARGLINE}`

この機能が失敗した場合探す一致するファイルが見つかりませんでした。次のエラーが発生しました。

'-name'コマンドが見つかりません。 'coreutils' (デフォルト) パッケージの 'uname' コマンドを意味します。 -name: コマンドが見つかりません。

ただし、findが一部のファイルを見つけるのにかかる日数がこの値に達すると、正常に機能します。成功した実行の出力を別のコマンドにパイプしようとすると失敗します。

「検索」の引数行をどのように適切に設定する必要がありますか?

答え1

ではbash配列を使用します。

args=( '(' -name 'FOO*.xml' -or -name 'BAR*.xml' -or -name 'BTT*.txt' ')' )

)を使用するので、正しいブール論理グループを作成するために追加の括弧が使用されます-or

find次に、コマンドで次の操作を行います。

find ...some arguments... "${args[@]}"

使用するため、追加の問題があります。

`$ARGLINE`

$( $ARGLINE )これは、シェルが$ARGLINE(対応する値)をコマンドとして実行しようとするのと同様のコマンドの置き換えです。これが「コマンド '-name'が見つかりません」というメッセージが表示される理由です。コマンドの置き換えは失敗しますが、find実行されるので「動作する」と思います。

答え2

ここで最大の問題は、引用符が引用符内で機能しないことです。変数を展開した後、内部引用符は次の一般的な文字にすぎません。

$ foo='foo "bar doo"'
$ printf "<%s>\n" $foo
<foo>
<"bar>
<doo">

次のコマンドパラメータを保存するには、配列を使用する必要があります。

ARGS=(-name 'FOO*.xml' -or -name 'BAR*.xml' -or -name 'BTT*.txt')

シェルはこのステップで引用符を処理し、異なるシェル単語を別の配列要素として保存します。次のような配列を使用します。

find . "${ARGLINE[@]}"

必要に応じて、または必要に応じて配列を1つずつ構成して同じ配列を作成できます。

ARGS=(-name 'FOO*.xml')
ARGS+=(-or -name 'BAR*.xml')
ARGS+=(-or -name 'BTT*.txt')

ただし、「引用」するために逆引用符も使用することに注意してください${ARGLINE}。これにより、コマンド置換が開始され、ARGLINEコンテンツがコマンドとして実行されます。ここでエラーが発生し、シェルというプログラムを実行しようとしています-name


実際、あなたの例ではそうではありません。必要パラメータにスペースがないため、配列です。ここで最大の問題は、一般に空白の違いです。〜サイパラメータとスペース以内にコマンドラインを文字列として保存すると、パラメータが失われます。ただし、お客様の場合、これはうまくいくかもしれませんが、お勧めしません。

set -f       # disable globbing
ARGLINE="-name FOO*.xml -or -name BAR*.xml -or -name BTT*.txt"
find . $ARGLINE

関連情報