sed를 사용하여 파일 이름 바꾸기


87

객관적인

다음 파일 이름을 변경하십시오.

  • F00001-0708-RG-biasliuyda
  • F00001-0708-CS-akgdlaul
  • F00001-0708-VF- 히 울기 글

다음 파일 이름에 :

  • F0001-0708-RG-biasliuyda
  • F0001-0708-CS-akgdlaul
  • F0001-0708-VF- 히 울기 글

쉘 코드

테스트하려면 :

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/'

수행하려면 :

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/' | sh

내 질문

sed 코드를 이해하지 못합니다. 대체 명령이 무엇인지 이해합니다.

$ sed 's/something/mv'

방법. 그리고 정규 표현식을 다소 이해합니다. 그러나 나는 여기서 무슨 일이 일어나고 있는지 이해하지 못합니다.

\(.\).\(.*\)

또는 여기 :

& \1\2/

전자는 "단일 문자, 단일 문자, 단일 문자의 길이 시퀀스"를 의미하는 것처럼 보이지만 확실히 그 이상의 의미가 있습니다. 후반부까지 :

& \1\2/

나는 모른다.


답변:


149

첫째,이를 수행하는 가장 쉬운 방법은 prename 또는 rename 명령을 사용하는 것입니다.

Ubuntu, OSX (Homebrew 패키지 rename, MacPorts 패키지 p5-file-rename) 또는 perl 이름 변경 (사전 이름)이있는 기타 시스템 :

rename s/0000/000/ F0000*

또는 RHEL과 같이 util-linux-ng에서 이름을 바꾸는 시스템 :

rename 0000 000 F0000*

동등한 sed 명령보다 훨씬 이해하기 쉽습니다.

그러나 sed 명령을 이해하려면 sed 맨 페이지가 도움이됩니다. man sed를 실행하고 &를 검색하면 (/ 명령을 사용하여 검색) s / foo / bar / 대체에서 특수 문자임을 알 수 있습니다.

  s/regexp/replacement/
         Attempt  to match regexp against the pattern space.  If success‐
         ful,  replace  that  portion  matched  with  replacement.    The
         replacement may contain the special character & to refer to that
         portion of the pattern space  which  matched,  and  the  special
         escapes  \1  through  \9  to refer to the corresponding matching
         sub-expressions in the regexp.

따라서에서 \(.\)참조 할 수있는 첫 번째 문자와 일치합니다 \1. 그런 .다음 항상 0 인 다음 문자 \(.*\)와 일치 합니다. 그런 다음에서 참조 할 수있는 나머지 파일 이름과 일치합니다 \2.

대체 문자열은 &(원래 파일 이름)을 사용하여 모든 것을 모으고 \1\2두 번째 문자 인 0을 제외한 파일 이름의 모든 부분입니다.

이것은 IMHO를 수행하는 꽤 비밀스러운 방법입니다. 어떤 이유로 rename 명령을 사용할 수없고 sed를 사용하여 이름을 변경하려는 경우 (또는 이름 바꾸기에 너무 복잡한 작업을 수행 했습니까?) 정규식에서 더 명시 적으로 지정하면 훨씬 더 읽기 쉽습니다. 아마도 다음과 같습니다.

ls F00001-0708-*|sed 's/F0000\(.*\)/mv & F000\1/' | sh

s / search / replacement /에서 실제로 변경되는 내용을 볼 수 있으면 훨씬 더 읽기 쉽습니다. 또한 실수로 두 번 또는 무언가를 실행하면 파일 이름에서 문자를 계속 빨아 들이지 않습니다.


1
내 RHEL 서버에서 이름 바꾸기 구문은 "rename 0000 000 F0000 *"입니다.
David LeBauer 2010

1
rename자체가 "이름이 바뀐" 링크 일 가능성이 큽니다 . 즉 rename"변경" 에서 prename우분투 .. 예 : readlink -f $(which rename)출력 /usr/bin/prename... rename언급 다윗 완전히 다른 프로그램이다.
Peter.O

1
좋은 지적이야, 피터. 두 가지 이름 바꾸기 유틸리티를 모두 해결하기 위해 답변을 업데이트했습니다.
Edward Anderson

3
이것을 디버깅하려면 끝에 sh로 파이프를 제거하십시오. 명령이 화면에 표시됩니다.
Ben Mathews

1
임의의 데이터를 통해 파이프에 제공하는 것이 좋은 조언 sh입니까? 이것은 임의의 코드가 실행될 수 있기 때문에 잠재적으로 위험합니다 (데이터를 코드로 취급합니다).
gniourf_gniourf dec

44

sed 설명을 마쳤습니다. 이제 셸만 사용할 수 있으며 외부 명령이 필요하지 않습니다.

for file in F0000*
do
    echo mv "$file" "${file/#F0000/F000}"
    # ${file/#F0000/F000} means replace the pattern that starts at beginning of string
done

1
좋지만 괄호로 참조 할 수 없습니다.
Leonidas Tsampros 2013 년

26

sed몇 년 전에 일괄 이름 변경에 대한 예제가 포함 된 작은 게시물을 작성했습니다 .

http://www.guyrutenberg.com/2009/01/12/batch-renaming-using-sed/

예를 들면 :

for i in *; do
  mv "$i" "`echo $i | sed "s/regex/replace_text/"`";
done

정규식에 그룹 (예 :)이 포함 \(subregex\된 경우 대체 텍스트 \1\에서 \2등 으로 사용할 수 있습니다 .


링크 전용 답변은 사용하지 않는 것이 좋습니다 (링크는 시간이 지남에 따라 오래된 경향이 있음). 여기에 답변을 수정하고 시놉시스를 추가해보세요.
클레오 파트라

그다지 효율적이지는 않지만 수백 개의 파일에 대한 작업을 수행합니다. 찬성.
Varun Chandak

21

가장 쉬운 방법은 다음과 같습니다.

for i in F00001*; do mv "$i" "${i/F00001/F0001}"; done

또는 이식 가능하게

for i in F00001*; do mv "$i" "F0001${i#F00001}"; done

이렇게 F00001하면 파일 이름 의 접두사가 F0001. mahesh에 대한 크레딧 : http://www.debian-administration.org/articles/150


3
변수 보간을 올바르게 인용해야합니다. mv "$i" "${i/F00001/F0001}". 하지만 +1
tripleee 2013 년

7

sed명령

s/\(.\).\(.*\)/mv & \1\2/

대체하는 의미 :

\(.\).\(.*\)

와:

mv & \1\2

일반 sed명령 과 같습니다 . 그러나 괄호 &\n마커는 약간 변경됩니다.

검색 문자열은 처음에 단일 문자와 일치하고 (패턴 1로 기억) 나머지 문자열이 뒤 따르는 단일 문자 (패턴 2로 기억 됨)가 뒤 따릅니다.

교체 문자열에서 이러한 일치 된 패턴을 참조하여 교체의 일부로 사용할 수 있습니다. 전체 일치 부분을 &.

따라서이 sed명령이 수행하는 작업은 mv원본 파일 (소스 용)과 문자 1 및 3을 기반으로 명령을 생성 하여 문자 2 (대상 용)를 효과적으로 제거하는 것입니다. 다음 형식에 따라 일련의 줄을 제공합니다.

mv F00001-0708-RG-biasliuyda F0001-0708-RG-biasliuyda
mv abcdef acdef

등등.


1
이것은 좋은 설명 이었지만 sed 명령을 다른 명령과 함께 사용하여 실제로 파일 이름을 바꾸는 방법을 지적하는 것이 유용 할 수 있습니다. 예 :ls | sed "s/\(.\).\(.*\)/mv & \1\2/" | bash
jcarballo 2014 년

@jcarballo : 구문 분석하는 위험 ls을, 파이프 sed쉘을 통해 다음 파이프! 위조 된 파일 이름으로 임의 코드 실행의 대상이됩니다. 문제는 데이터를 데이터로 취급해야한다는 것입니다. 여기서는 일반적으로 예방 조치없이 코드로 직렬화됩니다. 나는 paxdiablo가 실제로 좋은 연습을 보여주지 않기 때문에이 답변을 삭제할 수 있기를 바랍니다. (저는 초보자 | sh가 명령이 작동하지 않는 후 무작위로 파이프 하고이 질문과 답변을보고 더 잘 작동 할 것이라고 생각 했기 때문에이 질문을 우연히 발견했습니다 :). 무섭습니다!) .
gniourf_gniourf dec

3

backslash-paren 항목은 "패턴을 일치시키면서 여기에서 일치하는 항목을 붙잡 으십시오."라는 의미입니다. 나중에 대체 텍스트 쪽에서 "\ 1"(첫 번째 괄호 안에있는 블록), "\ 2"(두 번째 블록) 등으로 기억 된 조각을 다시 가져올 수 있습니다.


1

정말로하고있는 일이 두 번째 문자를 제거하는 것이라면 그것이 무엇이든 상관없이 다음과 같이 할 수 있습니다.

s/.//2

그러나 당신의 명령은 명령을 빌드하고 mv실행을 위해 쉘에 파이프합니다.

이것은 귀하의 버전보다 더 읽을 수 없습니다.

find -type f | sed -n 'h;s/.//4;x;s/^/mv /;G;s/\n/ /g;p' | sh

네 번째 문자는 find각 파일 이름 앞에 "./"가 붙기 때문에 제거됩니다 .


이 답변을 삭제할 수 있기를 바랍니다. OP의 매우 구체적인 경우에는 좋을지 모르지만, 이런 답을보고 이해하지 못하는 사람이 많고, | sh작동하지 않는 명령을 따라 무작위로 파이프 가 작동하기를 바라면서 보다 나은. 끔찍 해요! (그리고 그것은 좋은 습관이 아닙니다). 이해 하시길 바랍니다!
gniourf_gniourf dec

0

괄호는 백 슬래시 숫자에서 사용할 특정 문자열을 캡처합니다.


0
 ls F00001-0708-*|sed 's|^F0000\(.*\)|mv & F000\1|' | bash

끔찍하다! 임의의 코드 실행의 대상입니다 (질문의 특정 컨텍스트가 아닐 수도 있지만 이와 같은 답변을보고 비슷한 것을 무작위로 입력하려고 시도하는 많은 사람들이 있으며 위험합니다!). 이 답변을 삭제할 수 있기를 바랍니다 (게다가 여기에 다른 좋은 답변이 있습니다.
gniourf_gniourf dec

0

내가 할 일은 다음과 같습니다.

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done

그런 다음 괜찮아 보이면 | sh끝에 추가 하십시오. 그래서:

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done | sh

0

Perl 이름 바꾸기 사용 ( 도구 상자에 있어야 함 ) :

rename -n 's/0000/000/' F0000*

-n출력이 실제 이름을 바꾸는 것이 좋을 때 스위치를 제거하십시오 .

경고 이 작업을 수행 할 수 있거나 수행 할 수없는 동일한 이름을 가진 다른 도구가 있으므로주의하십시오.

util-linux패키지의 일부인 이름 바꾸기 명령 은 그렇지 않습니다.

다음 명령 ( GNU) 을 실행하면

$ rename

보시 perlexpr다시피 이것은 올바른 도구 인 것 같습니다.

그렇지 않은 경우 기본값 (일반적으로 이미있는 경우)으로 설정 Debian하고 다음과 같이 파생합니다 Ubuntu.

$ sudo apt install rename
$ sudo update-alternatives --set rename /usr/bin/file-rename

archlinux의 경우 :

pacman -S perl-rename

RedHat 제품군 배포판의 경우 :

yum install prename

'prename'패키지는 EPEL 저장소에 있습니다.


Gentoo :

emerge dev-perl/rename

* BSD의 경우 :

pkg install gprename

또는 p5-File-Rename


Mac 사용자의 경우 :

brew install rename

다른 배포판에이 명령이없는 경우 패키지 관리자를 검색하여 설치하거나 수동으로 수행하십시오 .

cpan -i File::Rename

이전 독립 실행 형 버전은 여기 에서 찾을 수 있습니다 .


남자 이름 바꾸기


이 도구는 원래 Perl의 아빠 인 Larry Wall이 작성했습니다.


-1
for i in *; do mv $i $(echo $i|sed 's/AAA/BBB/'); done

4
SO에 오신 것을 환영합니다. 코드에 대한 설명을 추가해보십시오. 다른 사용자가 그것을 이해하는 데 도움이 될 것입니다.
Digvijay S

이 답변은 좋지만 위의 높은 찬성 답변과 거의 중복되는 답변입니다.
Eric Leschinski
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.