私は仕事でAppleScriptsのワークフローを捨て、バックグラウンドで実行できるより簡単なものを作成したいと思います。これを行うには、毎晩35〜40ファイル(7〜8ファイルの5つの品質バージョン)を受け取り、ファイル名の一部を抽出する必要があります。
たとえば、これらのファイルの配置(省略)は次のとおりです。
各ファイルには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番目のバージョンまで抽出することですです。最後_
。これまでの最初の部分を完了できましたが、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
それから私は次のことを得ることを考えてみました(私はオンラインのすべてのRegExテスター、特に私が見つけることができるPerl RegExテスターがうまくいくと言ったことに基づいています)。
$ 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番目の最後の位置で一致を停止して.awkを設定すると、awkが最後の位置を維持するために肯定的な予測が必要になります。_
__
{$NL=$(NL-1)=""; print $0}
答え1
オプション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)
答え2
からファイルリストをフィルタリングする代わりに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
拡張は、最後から2番目の文字から文字列の終わりまでの文字を削除し、${1%_*_*}
結果に含まれるファイルパスを削除します。_
basename
find
構造
-exec sh -c `blah blah` sh {} \;
学び、使用する価値がありますfind
。 @Kusalanandaには素晴らしい記事があります。ここ
-exec
find
出力に対して「何かしらと」を実行するように指示します\;
。言い換えれば、各結果に対して個別に「何か、あまりにも」実行することを意味します。これはsh -c 'put some script in here'
結果として行われることであり、最後にsh {}
出力をfind
次に定義されたスクリプトに戻します。sh -c