ある変数に対するgrepコマンドの結果を別の変数にインポートする方法

ある変数に対するgrepコマンドの結果を別の変数にインポートする方法

指定された条件に一致するディレクトリのファイルを一覧表示します。ディレクトリ内の各ファイルに対して実行したいことの1つは、6桁の日付を抽出して変数に入れることです。私のスクリプトは現在次のとおりです

for i in $(ls $INPUT_DIR | egrep -i '^'$INPUT_FILE_PREFIX'[0-9][0-9]([0][1-9]|1[0-2])([0][1-9]|[12][0-9]|[3][01])'$INPUT_FILE_SUFFIX); do   
 MYDATE=$("$i" | grep -oP '\d{6,6}')
 echo $MYDATE
done

上記の結果はエラーです"somefile": command not found

MYDATE=$("$i" | grep -oP '\d{6,6}')私にとって奇妙なことはecho "$i" | grep -oP '\d{6,6}'

"$i"スクリプトがコマンドの代わりに文字列として渡されるようにするにはどうすればよいですか?

答え1

ファイル名から。で$INPUT_FILE_PREFIX始まり、終わる6桁の数字を解析したいようです$INPUT_FILE_SUFFIX

これを行うことができます:

for name in "$INPUT_DIR/$INPUT_FILE_PREFIX"??????"$INPUT_FILE_SUFFIX"; do
    test -f "$name" || continue

    number=${name#$INPUT_DIR/$INPUT_FILE_PREFIX}
    number=${number%$INPUT_FILE_SUFFIX}

    printf "Number = %s\n" "$number"
done

数字のみが一致することを確認するには(該当する文字が何でも単一文字と一致する)、すべて?をに変更します。[0-9]?

ループのパラメータ置換は値の最初の部分を削除し、残りの$name文字列の最後の部分を削除し、中間数字(プレフィックスとサフィックスの間の6文字)のみを変数に残します$number


注文する

MYDATE=$("$i" | grep -oP '\d{6,6}')

見つかったとおり、$i呼び出しコマンドに含まれるすべての内容が解釈されます。また、echo前に置くとうまく"$i"いくと言いました。そしてそれははい:

MYDATE=$(echo "$i" | grep -oP '\d{6,6}')

あなたのコードに関連:なぜ`ls`を解析しないのですか?

答え2

bashを使用してファイル名を繰り返す少し異なる方法をお勧めします。拡張ワイルドカードファイル名の収集:

shopt -s extglob
for d in "${INPUT_DIR}"/"${INPUT_FILE_PREFIX}"[0-9][0-9]@(0[1-9]|1[0-9])@(0[1-9]|[12][0-9]|3[01])"${INPUT_FILE_SUFFIX}"
do 
  [[ $d =~ ${INPUT_FILE_PREFIX}([[:digit:]]+)${INPUT_FILE_SUFFIX} ]]
  MYDATE=${BASH_REMATCH[1]}
done

ワイルドカード構文はgrepステートメントとほぼ同じです。各グループは、@(...)で区切られた特定のパターンに一致する要求を紹介します|。私が見つけたパターン(日付仮定)[3]は単一文字クラスなので、その周りの角かっこを削除しました。

ループにファイル名がある場合は、条件式のforbash の正規表現演算子を使用して=~数値を MYDATE で削除できます。

答え3

for i in $(ls $INPUT_DIR | egrep -i '^'$INPUT_FILE_PREFIX'[0-9][0-9]([0][1-9]|1[0-2])([0][1-9]|[12][0-9]|[3][01])'$INPUT_FILE_SUFFIX);

ls通常、このような構造では使用する理由はありません。コマンドを読みにくくし、いくつかのコーナーケースの問題に直面するだけです(参照:BashGuideでの解析)。しかし、あなたが持っている正規表現は標準シェルglobで表現することはできませんので、それを使うのは合理的です。タグがついているので、シェルでこれを行うか、次を使用できます。extglob[[ .. ]](または正規表現を使用して、より広いglob-after構成と一致させます。)

shopt -s extglob
for i in "$INPUT_DIR/$INPUT_FILE_PREFIX"[0-9][0-9]@(0[1-9]|1[0-2])@(0[1-9]|[12][0-9]|3[01])"$INPUT_FILE_SUFFIX" ; do

そのような厳格なパターンが本当に必要でない場合は、単に使用することができます[0-9][0-9][0-9][0-9][0-9][0-9]

ペア割り当てでは、MYDATEプレフィックスとサフィックスのみを削除したいとします。 (プレフィックス/サフィックスに6桁の文字列が含まれている場合、grepもその文字列と一致します。)

MYDATE=${i#"$INPUT_DIR/"}              # remove the directory
MYDATE=${MYDATE#"$INPUT_FILE_PREFIX"}  # remove the prefix
MYDATE=${MYDATE%"$INPUT_FILE_SUFFIX"}  # and the suffix

すべて:

shopt -s extglob
for i in "$INPUT_DIR/$INPUT_FILE_PREFIX"[0-9][0-9]@(0[1-9]|1[0-2])@(0[1-9]|[12][0-9]|3[01])"$INPUT_FILE_SUFFIX" ; do
    MYDATE=${i#"$INPUT_DIR/"}              # remove the directory
    MYDATE=${MYDATE#"$INPUT_FILE_PREFIX"}  # remove the prefix
    MYDATE=${MYDATE%"$INPUT_FILE_SUFFIX"}  # and the suffix
    echo "$MYDATE"
done

答え4

試してみましたか?Bashプロセスの交換?コマンド方式が簡単になり、ループや変数が不要なようです。

基本的に、プロセスの置き換えはよく知られていませんが、非常に強力です。

プロセス置換は、あるプロセス(またはプロセス)の出力を別のプロセスの標準入力に供給します。

したがって、コマンドは次のように単純化できます。

grep -oP '\d{6,6}'<(egrep -i '^'$INPUT_FILE_PREFIX'[0-9][0-9]([0][1-9]|1[0-2])([0][1-9]|[12][0-9]|[3][01])'$INPUT_FILE_SUFFIX <(ls $INPUT_DIR))

その背後にあるロジックは、より単純なバージョンでよりよく理解できます。

user@yrmv-191108:~/nums$ ls .
1  10  2  3  4  5  6  7  8  9
user@yrmv-191108:~/nums$ grep 1 <(ls .)
1
10

関連情報