ファイルから配列をgrepし、検索パターンを再利用します。

ファイルから配列をgrepし、検索パターンを再利用します。

シェルスクリプトを介して実行したいプロジェクトがあります。

私は約30年間持続してきた長期間の毎週のラジオ番組カタログを持っています。ソースが異なるため、名前の形式もかなり異なる場合があります。これにより、私が持っているショーと欠けているショーが何であるかを知ることは困難です。

標準の日付形式でシンボリックリンクを作成し、ファイル名を実際の表示ディレクトリ(ある場合)への日付シンボリックリンクとして使用したいと思います。

たとえば、私が言いたいことは

'2015-09-25' -> '../Radio Show/2015-09-25 Special Guest/'
'2015-10-02' -> '../Radio Show/Very funny! 2015-10-02 Show'

日付形式も多様ですが、今はYY-MM-DD、YYYY-MM-DD形式を探すのが悩みだけです。

だから私は以下を使用して各行がから1980-01-01の日付であるファイルを作成しました。2010-12-31この回答

次に各行を読み取り、それを使用して名前に対応するfind文字列を含むディレクトリを見つけます。ただし、find30年前のすべての日付に対してディレクトリツリー全体で作業を実行するには時間がかかります*。

だから私はfind -type d . > filesystem.txtすべてのディレクトリ名を含むファイルを作りました。その後、grep各日付文字列に対してディスク上で実行するのではなく、そのファイルの各日付文字列に対して実行できますfind

ただし、日付ファイルの各行をgrepにロードするのに問題があります。

Butを使用すると、$ grep -f dates.txt filesystem.txt 次の形式ですべての結果を取得できます。

./complete/1996-02-18
./complete/1996-03-03
./complete/1996-03-31
...

文字列パラメータを使用して結果を取得する方法がわかりません。

'1996-03-31' -> './complete/1996-03-31'

私はこれを試しましたが、$ grep "${dates[@]}" metadata/filesystem.txt期待どおりに動作しません。

grep: 1988-01-03: No such file or directory
grep: 1988-01-04: No such file or directory

私がやりたいことの擬似コードのバージョンは次のとおりです。

foreach ( date-string in dates.txt ) {
  grep date-string in filesystem.txt
  if (match) {
     ln -s match date-string
  }
}

Bashでどうすればいいですか?

-*すべての日付を使用しないことでこれを簡素化できますが、ラジオ番組がすべての記録で同じ日に行われるかどうかはわかりません。日付を見逃していないことを確認したいので、30年の範囲内のすべての日付を使用したいと思います。

答え1

トピックの質問に答えてください。grepを使って配列内の要素を見つける方法

a=(foo bar baz)
grep "${a[@]}" files

する:

grep foo bar baz files

つまり、検索fooしたり、望むものではありませんbarbazfiles

あなたが望むもの:

grep 'foo
bar
baz' files

代わりに。これを行うには、次の手順を実行します。

IFS=$'\n'
grep -- "${a[*]}" files

構文を使用すると、最初の文字$IFSは配列の要素を連結するために使用されます"${a[*]}"。これは配列をサポートするすべてのシェルで動作します(ksh、、、、(その部分はまだ機能していませんが、リテラル改行文字を使用する必要があります))。zshbashyash$'\n'yash

を使用すると、zsh次の操作も実行できます。

grep -e$^a files

これは次のように拡張されます。

grep -efoo -ebar -ebaz files

これは別の文字列を検索する別の方法です。

(配列に一致させる正規表現の代わりに検索する固定文字列が含まれている場合は、このオプションを使用する必要があります-F。)

答え2

そしてzsh

autoload zmv # best in ~/.zshrc
zmv -Ls -n '../Radio Show/(^*[0-9])((19|)(<80-99>~^??)|(20|)(<0-16>~^??))(-<1-12>-<1-31>~^-??-??)(^[0-9]*)' '${4:+19$4}${6:+20$6}$7'

-n乾式実行に使用されます。提案されたタスクが満足のいくものであれば、削除して実際にリンクを作成してください。

zmvファイルの競合や上書きを防ぐ役割を担います。具体的なzshグローバル演算子は次のとおりです。

  • <1-12>1から12までの10進整数で識別される文字列と一致します。 2012年の012に一致します。
  • ^x: 否定
  • x~y(and-not):yと一致しない限り、xと一致する文字列。したがって、<1-12>~^??1から12までの2桁の数字と一致します(01と一致しますが、1または0001は一致しません)。
  • (x|y):EREのように置き換えられます。

欠落している19または20日付をYY-MM-DD形式で挿入します。

答え3

John1024の答えはおそらく最高です。しかし、完全性のために、疑似コードの実装は次のとおりです。

for datestring in $(cat dates.txt)
do if match="$(grep "$datestring" filesystem.txt)"
   then echo ln -s "$match" "$datestring"
   fi
done

inを残したechoので、削除するまでは何もしません。ただし、上記はすべての日付をパラメータに拡張する必要があるため、以下を優先する必要があります。

while read datestring
do if match="$(grep "$datestring" filesystem.txt)"
   then echo ln -s "$match" "$datestring"
   fi
done <dates.txt

$datestring空白がないことを知りながら、二重引用符を追加して何も変更しないようにしました。

答え4

私が正しく理解した場合は、次のfilesystem.txtファイルがあります。

$ cat filesystem.txt 
../Radio Show/Very funny! 2015-10-02 Show
../Radio Show/2015-09-25 Special Guest/

考えてみてください:

$ sed -E 's/.*[^[:digit:]]([[:digit:]]{2,4}-[[:digit:]]{2}-[[:digit:]]{2}).*/ln -s "&" "\1"/' filesystem.txt >script

上記のコマンドは、一連のコマンドのように見えるコマンドを生成しますscriptscriptbash

$ cat script
ln -s "../Radio Show/Very funny! 2015-10-02 Show" "2015-10-02"
ln -s "../Radio Show/2015-09-25 Special Guest/" "2015-09-25"

このファイルを確認し、必要に応じて実行してください。

bash script

関連情報