본문 바로가기
Perl-공부하기

[perl] xargs 를 활용한 파일 이름 변경 예제

by Thdnice 2021. 8. 9.
반응형

xargs 는 표준 입력을 다음 명령어의 arguments 로 변환시켜주는 unix 명령어이다.


예를들어 파일을 지우는 rm 명령어의 경우

rm (filename)



이런식으로 사용하는데, 이 경우 뒤에 (filename) 이 부분이 명령 인자(argument)에 해당된다.
물론 wildcard 등을 이용해서 한 번에 많은 파일을 지우거나, 폴더 전체의 파일을 지울 수 도 있다.

rm *



하지만 만약 특정 pattern 만 취해서 파일을 삭제 하고 싶다면? 
예를들어 중간에 (_old_) 라는 단어가 들어간 파일만 지우고 싶다면 아래처럼 

ls | grep "_old_" | xargs rm


여러개의 명령어를 조합하여 실행시킬 수 있다. 이 경우 grep 에서 정규표현식을 사용할 수 있다는 점에서
그리고 xargs를 통해 rm명령어에 인자를 넘겨주기 전에 실제 어떤 파일이 삭제 될 예정인지 확인해볼 수 있다는 점에서 기존의 rm 에 wildcard 를 사용하는 것 보다 강력하고 유용하다. 

그리고 xargs 를 사용하면 얻어지는 이 점이 하나 있는데 바로 특수문자(띄어쓰기 등이 포함된)가 포함된 파일명등에 대해서도
별도의 이스케이프 문자 없이 다룰 수 있다는 점이다.

예를들어 

'Old File 1.txt'
'Old File 2.txt'
'Old File 3.txt' 

와 같은 파일들을

'NewFileName0001.txt' 

이런식으로 패딩하여 이름을 바꾼다고 해보자. 이런건 perl 을 사용해서도 할 수 있는데 

ls *.txt | grep "Old File"


이렇게 하면 일단 대충 Old File ~~~ .txt 인 파일들을 발라낼 수 있고, 여기서 일단 숫자만 건져보면

ls *.txt | grep "Old File" | perl -nle '/([0-9]+)/ and print "$1"'


처럼해서

1
2
3
...

등을 발라낼 수 있다. 우리는 이 숫자를 0001, 0002 처럼 4자리 숫자로 패딩하길 원했으므로 아래처럼 formatting 을 맞춰서 

ls *.txt | grep "Old File" | perl -nle '/([0-9]+)/ and printf"NewFileName%04d.txt\n",$1'


로 바꿔주면 이제 target name 은 완성이 되었다.  또한 source file name 은 앞에서 표준 입력으로 넘어오는 그 자체이므로( $_ ) 별도 처리 없이

ls *.txt | grep "Old File" | perl -nle '/([0-9]+)/ and printf"mv $_ NewFileName%04d.txt\n",$1'


을 쓰면 내가 하고자하는 명령 그 자체는 문제가 없는데, 여기서 문제는 $_ 에 빈칸이 있다는 점이다. 위 결과를 그대로 bash 에 넘겨보면 에러가 난다. 
나는 'Old File 1.txt' 를 하나의 파일로 (즉, shell 입장에서 Old\ File\ 01.txt) 로 생각했지만, 이를 문자열로 printf 하다 보니, 이게 단어 단어 띄어쓰기로 구분되어
mv 에 여러 인자가 들어가는 것과 같은 효과를 주는 것이다.

따라서 특수문자, 특히 띄어쓰기가 있는 경우에는 이걸 하나의 인자로 넘겨줘야 하는데 이를 위해서 앞 뒤를 작은 따옴표로 감싸는 방법도 있지만, 그보다 더 쉬운 방법이 이걸 그냥 인자로 던져주면 된다. 바로 xargs 를 사용하는 방법!

물론 xargs 도 앞에서 오는 표준 입력이 어떻게 구분되는지 알 수 없다. 따라서 이를 특정 구분자(delinator)로 구분해줘야 하는데  예를들어 앞에서 인자마다 한줄씩 띄워준다면 이 경우 delininator 는 개행 ("\n") 이 된다.  

ls *.txt | grep "Old File" | perl -nle '/([0-9]+)/ and printf"$_\nNewFileName%04d.txt\n",$1'


따라서 old name / new name 을 모두 한 줄 씩 띄워서 출력하고, xargs 에서 구분자를 알려주면 (-d 옵션) 이제 인자를 구분해서 받는다. 그리고 이름을 변경할 시에는 한 번에 2개씩 필요하니 -n 옵션으로 여러개의 인자가 오면 2개씩 짝지어서 사용하게 해준다. 

 

ls *.txt | grep "Old File" | perl -nle '/([0-9]+)/ and printf"$_\nNewFileName%04d.txt\n",$1' | xargs -d "\n" -n2 mv

 

이제 해석하면 앞에서 perl 을 통해 출력된 문자열을 개행문자 기준으로 하나씩 인자로 취급해서 mv 라는 명령어의 첫번째, 두번째 인자 (souce file / target file) 로 넣어준다.

xargs 명령어가 낯설다면, -p 옵션을 쓰는것도 좋다. 이 경우 실행될 명령어를 한줄씩 출력해서 나타내므로 내가 원하는 실행이 맞는지 확인하고 실행할 수 있다.

 

 

 

반응형

'Perl-공부하기' 카테고리의 다른 글

정규표현식  (0) 2022.03.03
Perl Tutorial - 4. Count Lines 3  (0) 2020.12.31
Perl tutorial - 3. Count lines 2  (0) 2020.12.31
Perl Tutorial - 2. Count Lines  (0) 2020.12.28
Perl Tutorial 01 - Hello world  (0) 2020.12.20