
指定された条件に一致するディレクトリのファイルを一覧表示します。ディレクトリ内の各ファイルに対して実行したいことの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]
は単一文字クラスなので、その周りの角かっこを削除しました。
ループにファイル名がある場合は、条件式のfor
bash の正規表現演算子を使用して=~
数値を 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