저는 직장에서 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한 다음(복사하는 데 가장 오랜 시간이 걸리므로 해당 파일이 있으면 나머지 파일도 거기에 있음) 모든 것을 두 번째 버전까지 추출하는 것입니다. 마지막 _
. 지금까지 첫 번째 부분을 완료할 수 있었지만 두 번째 부분은 완료하지 못했습니다.
이렇게 하면 가장 높은 버전 목록만 표시됩니다.
$ 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를 사용하는 것이 좋을 수도 있다고 생각했습니다. 그러나 ( 문자열의 처음부터 계산하는 _
대신 ) 두 번째에서 마지막 위치에서 일치를 중지하고 .awk를 설정하면 awk가 마지막 위치를 유지 하도록 긍정적인 예측이 필요합니다 ._
__
{$NL=$(NL-1)=""; print $0}
답변1
옵션이 perl
있으므로 명령을 사용하면 항상 해당 줄을 인쇄할 수 있습니다. -p
일치하는 부분은 아무 작업도 수행하지 않습니다.
일치하는 부분을 원 -n
하고 인쇄합니다.
ls -1 *9000.jpg \
| perl -lne 'print $1 if /^(.+)(?=_.+_.+)/'
파일 이름에 개행 문자가 있을 수 있으므로 0으로 구분된 파일 이름을 읽도록 수정해야 하지만 귀하의 경우에는 필요하지 않을 수도 있습니다.
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
확장은 마지막에서 두 번째 문자부터 문자열 끝까지의 문자를 제거하고 ${1%_*_*}
결과에 포함된 파일 경로를 제거합니다._
basename
find
구조
-exec sh -c `blah blah` sh {} \;
배우고 사용할 가치가 있습니다 find
. @Kusalananda에는 훌륭한 기사가 있습니다.여기
-exec
find
출력에 대해 "어쩌고 저쩌고"를 수행하라고 지시합니다 \;
. 즉, 각 결과에 대해 개별적으로 "어쩌고 저쩌고" 수행하라는 의미입니다. 이것이 sh -c 'put some script in here'
결과로 수행하려는 작업이고 마지막으로 sh {}
출력을 find
다음에 정의된 스크립트로 다시 전달합니다.sh -c