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.