私は自分の仕事のワークフローのためにAppleScriptsから離れて、代わりにバックグラウンドで実行できるより単純なものを作成しようとしています。このタスクでは、毎晩35〜40個のファイル(異なる品質の7個または8個のファイルの5つのレンディション)が与えられ、ファイル名の一部を抽出する必要があります。
例として、これらのファイルの1つの(省略された)バッチがどのように見えるかを次に示します。
各ファイルには5つのレンディションがあります
ab_12_345_01_dest_xxxxxxxxxx_640x360_1000.jpg
ab_12_345_01_dest_xxxxxxxxxx_768x432_3000.jpg
ab_12_345_01_dest_xxxxxxxxxx_960x540_5000.jpg
ab_12_345_01_dest_xxxxxxxxxx_1280x720_7000.jpg
ab_12_345_01_dest_xxxxxxxxxx_1920x1080_9000.jpg
そして、ファイルはすべてそのように名前が付けられています(最高のレンディションを使用して、理由はすぐにわかります):
ab_12_345_01_dest_xxxxxxxxxx_1920x1080_9000.jpg
ab_12_345_02_dest_yyyyyyyyyy_1920x1080_9000.jpg
ab_12_345_03_dest_zzzzzzzzzz_1920x1080_9000.jpg
ab_12_345_part1_aaaaaaaaaa_1920x1080_9000.jpg
ab_12_345_part2_bbbbbbbbbb_1920x1080_9000.jpg
ab_12_345_part3_special_cccccccccc_1920x1080_9000.jpg
ab_12_345_part4_dddddddddd_1920x1080_9000.jpg
ab_12_345_04_dest_special_eeeeeeeeee_1920x1080_9000.jpg
したがって、私の目標は、ファイル名の9000
部分を使用して、それぞれの最高のレンディションのみをgrepすることです(コピーするのに最も時間がかかるため、そこにある場合は、残りのファイルもそこにあります)。最後から2番目の_
。これまでのところ、パート1は実行できましたが、パート2は実行できませんでした。
これを行うと、最高のレンディションのみのリストを取得できます。
$ ls | grep 9000
ab_12_345_01_dest_xxxxxxxxxx_1920x1080_9000.jpg
ab_12_345_02_dest_yyyyyyyyyy_1920x1080_9000.jpg
ab_12_345_03_dest_zzzzzzzzzz_1920x1080_9000.jpg
ab_12_345_part1_aaaaaaaaaa_1920x1080_9000.jpg
ab_12_345_part2_bbbbbbbbbb_1920x1080_9000.jpg
ab_12_345_part3_special_cccccccccc_1920x1080_9000.jpg
ab_12_345_part4_dddddddddd_1920x1080_9000.jpg
ab_12_345_04_dest_special_eeeeeeeeee_1920x1080_9000.jpg
次に、ls | grep 9000 | Perl -pe '/^.+(?=_.+_.+)/mg
を試してみました(すべてのオンライン正規表現テスター、具体的には、私が見つけたPerl正規表現テスターが機能すると言ったことに基づいて):
$ ls | grep 9000 | Perl -pe '/^.+(?=_.+_.+)/mg`
ab_12_345_01_dest_xxxxxxxxxx
ab_12_345_02_dest_yyyyyyyyyy
ab_12_345_03_dest_zzzzzzzzzz
ab_12_345_part1_aaaaaaaaaa
ab_12_345_part2_bbbbbbbbbb
ab_12_345_part3_special_cccccccccc
ab_12_345_part4_dddddddddd
ab_12_345_04_dest_special_eeeeeeeeee
しかし、Perlにパイプしたことがない場合と同じ結果が得られました。私はもともとawkでこれを実装しようとしましたが、入力していたコマンドがかなり長くなり、RegExがその方法かもしれないと考えました。ただし、(文字列の先頭から数えた_
ではなく)最後から2番目の_
で一致を停止するには、前向きな先読みが必要であり、{$NL=$(NL-1)=""; print $0}
を設定したときにawkは最後の__
を保持していました。 。
Perl
コマンドでは、-p
オプションがあるため、常に行を出力します。マッチパートは何もしません。
-n
が必要で、一致する部分を印刷します。
ls -1 *9000.jpg \
| Perl -lne 'print $1 if /^(.+)(?=_.+_.+)/'
ファイル名には改行が含まれている可能性があるため、これを変更してゼロで区切られたファイル名を読み取る必要がありますが、必要ない場合は次のようにします。
printf '%s\0' *9000.jpg \
| Perl -lne 'INIT{ $/ = "\0"}; print $1 if /^(.+)(?=_.+_.+)/'
または、forループでファイル名を読み取り、シェルのみのパラメーター展開を使用できます。
for f in *9000.jpg; do printf '%s\n' "${f%_*_*}"; done
これはあなたの仕事により適しているかもしれません。 (=>「ファイル名に行ベースのテキスト編集ツールを使用しないでください。」@ Kusalananda)
ファイルリストをフィルタリングするためにls
からgrep
にパイプする必要はありません。
ls *9000.jpg
また、grep
を使用すると、名前の他の場所に9000が含まれているファイルがすべて選択されます。
正規表現に問題はなく、Perl
だけに問題があります。 grep
を使用すると、必要なものを取得できます
ls *9000.jpg | grep -Po "^.+(?=_.+_.+)"
これを行う別の方法は、
find . -iname "*9000.jpg" -exec sh -c 'basename ${1%_*_*}' sh {} \;
find
はls
と同じことをします
展開${1%_*_*}
は、最後から2番目の_
から文字列の終わりまで文字を削除し、basename
はfind
が結果に含めるファイルパスを削除します。
構成
-exec sh -c `blah blah` sh {} \;
find
で使用することを学ぶ価値は十分にあり、@ Kusalanandaには良い投稿があります ここ
-exec
はfind
にその出力で 'blah blah'を実行するように指示します。\;
は各結果で 'blah blah'を実行することを意味します。sh -c 'put some script in here'
はあなたがしたいことです結果を処理し、最後にsh {}
がfind
からの出力をsh -c
で定義されたスクリプトに戻します。