여러 파일의 일괄 이름 바꾸기를 위한 쉘 문

여러 파일의 일괄 이름 바꾸기를 위한 쉘 문

내가 찾고 있어요두 줄의 이름 바꾸기내 음악 라이브러리를 관리해 보세요.

첫 번째걱정하다파일 이름. 가능한 가장 간단한 이름을 사용하고 싶습니다. 예 %track %title.ext : 01 Song name.mp3 13 Song title.flacetc. 나는 현재 파일의 구분 기호(트랙 번호와 노래 제목 사이)로 하이픈을 사용하는데, 이는 중복된다고 생각합니다.

두번째걱정하다폴더 이름, 좀 바꿔야겠어요무늬 From GENRE - Styles - ARTIST - Album (Year) to GENRE - Styles - ARTIST - Year Album (연도 전환 및 앨범 부분도 괄호 생략)

(저는 openbsd를 실행합니다.크쉬 88.)

그것은 내가 만들어낸 가장 가까운 선입니다.파일 이름사례: for f in * ; do mv "$f" "$(print "$f" | sed "s/ - / /")" ; done 하지만 아직 작동하지 않았습니다. 나는 이것이 명령의 두 번째 인수(대상)를 올바르게 캡슐화하는 것과 관련이 있다고 생각합니다 mv(편집하다: 따옴표를 추가하면 $( ... )작동하지만 예상하지 못했습니다)

$pwd 
/home/media/E - Chanson Française/CHANSON - Chanson Française - CHARLES TRENET - Le meilleur de Charles Trenet
$l -1
01 - Boum!.flac
02 - La route enchantée.flac
03 - Ah! Dis, Ah! Dis, Ah! Bonjour!.flac
04 - La vie qui va.flac
05 - Quand j'etais p'tit.flac
06 - Ménilmontant.flac
07 - Tout me sourit.flac
08 - Le oiseaux de Paris.flac
...
$for f in * ; do mv "$f" "$(print "$f" | sed 's/ - / /')" ; done
$l -1
01 Boum!.flac
02 La route enchantée.flac
03 Ah! Dis, Ah! Dis, Ah! Bonjour!.flac
04 La vie qui va.flac
05 Quand j'etais p'tit.flac
06 Ménilmontant.flac
07 Tout me sourit.flac
08 Le oiseaux de Paris.flac
...

큰따옴표를 중첩하면 오류가 발생할 것이라고 생각했지만 작동합니다. 이로써 첫 번째 사건은 해결됐다.

이것폴더 이름그 사건은 나를 더욱 피하게 만들었다. 다음은 변경하려는 이름의 예입니다.

$ ls -1
...
ELECTRO - Cyberpunk - CARPENTER BRUT - Blood Machines (2020)
ELECTRO - Cyberpunk - CARPENTER BRUT - Leather Teeth (2018)
ELECTRO - Cyberpunk - CARPENTER BRUT - Leather Terror (2022)
ELECTRO - Cyberpunk - CARPENTER BRUT - Trilogy (2015)
...
REGGAE - Roots - GROUNDATION - Each One Teach One (2001)
REGGAE - Roots - GROUNDATION - Hebron Gate (2002)
REGGAE - Roots - GROUNDATION - Upon the Bridge (2006)
REGGAE - Roots - GROUNDATION - Young Tree (1999)
...

결과는 다음과 같아야 합니다.

$ ls -1
...
ELECTRO - Cyberpunk - CARPENTER BRUT - 2015 Trilogy
ELECTRO - Cyberpunk - CARPENTER BRUT - 2018 Leather Teeth
ELECTRO - Cyberpunk - CARPENTER BRUT - 2020 Blood Machines
ELECTRO - Cyberpunk - CARPENTER BRUT - 2022 Leather Terror
...
REGGAE - Roots - GROUNDATION - 1999 Young Tree
REGGAE - Roots - GROUNDATION - 2001 Each One Teach One
REGGAE - Roots - GROUNDATION - 2002 Hebron Gate
REGGAE - Roots - GROUNDATION - 2006 Upon the Bridge
...

필드를 전환하려면 awk를 사용해야 할 것 같습니다. for f in *CARPENTER\ BRUT* ; do mv "$f" "$( print "$f" | awk ... )" ; done마지막 하이픈 다음 연도를 awk로 전환하고 tr로 대괄호를 제거할 수도 있지만 이를 배우는 데 어려움을 겪고 있습니다.

답변1

zsh를 설치할 수 있는 경우:

  • XX - title.flac일반 파일 에 XX title.flac.

    zsh <<\EOF
      autoload zmv
      zmv -n '(**/)(<-> )- (*.(#i)(ogg|mp3|flac))(#q.)' '$1$2$3' < /dev/tty
    EOF
    
  • GENRE - Styles - ARTIST - Album (Year)GENRE - Styles - ARTIST - Year Album디렉토리 로

    zsh <<\EOF
      autoload zmv
      zmv -n '(**/)(* - * - * - )(*) \((<->)\)(#q/)' '$1$2$4 $3' < /dev/tty
    EOF
    

만족스러우면 삭제 -n(테스트 실행)합니다.

zsh를 설치할 수 없는 경우 findand를 사용 perl하면 다음과 같은 결과를 얻을 수 있습니다.

  • XX - title.flacXX title.flac일반 파일 로

    LC_ALL=C find . -depth -name '[0-9]*.*' -type f -print0 |
      perl -l -0ne '
        ($dir, $base) =  m{^(.*/)(.*)\z}s;
        if ($base =~ s/^(\d+ )- (.*\.(?i:ogg|mp3|flac))\z/$1$2/s) {
          print qq(rename($_, "$dir$base")) or warn "$_: $!";
        }'
    
  • GENRE - Styles - ARTIST - Album (Year)GENRE - Styles - ARTIST - Year Album디렉토리 로

    LC_ALL=C find . -depth -name '*(*)' -type d -print0 |
      perl -l -0ne '
        ($dir, $base) =  m{^(.*/)(.*)\z}s;
        if ($base =~ s/( - .* - .* - )(.*) \((\d+)\)\z/$1$3 $2/is) {
          print qq(rename($_, "$dir$base")) or warn "$_: $!";
        }'
    

그리고 만족스러우면 print qq(...) 주변을 삭제하세요.rename()

하지만 주목할 점은 다음과 같습니다.

  • 또한 숨겨진 파일/디렉토리(및 숨겨진 디렉터리 내)도 처리합니다.
  • 보호 기능이 없으므로 zmv결국 기존 파일을 덮어쓸 수 있습니다.

OpenBSD의 ksh 및 기본 POSIX 유틸리티를 사용하여 이를 수행하는 것이 가능하지만 매우 투박합니다.

가능한:

  • XX - title.flac일반 파일 에 XX title.flac.

    LC_ALL=C find . -depth -name '[0-9][0-9] - *' '(' \
      -name '*.[Ff][Ll][Aa][Cc]' -o \
      -name '*.[Oo][Gg][Gg]' -o \
      -name '*.[Mm][Pp]3' ')' -type f -exec ksh -c '
      for file do
        dir=${file%/*} base=${file##*/}
        print -r mv -i -- "$file" "$dir/${base%% *}${base#* -}"
      done' {} +
    
  • GENRE - Styles - ARTIST - Album (Year)GENRE - Styles - ARTIST - Year Album디렉토리 로

    LC_ALL=C find . -depth -name '* - * - * - * (*[0-9])' -type d -exec ksh -c '
      for file do
        dir=${file%/*} base=${file##*/}
        if [[ $base = *" ("+([0-9])")" ]]; then
          album="${base##* - }"
          year=${album##*\(}
          year=${year%\)}
          base=${base%"$album"}
          album=${album%" ("*}
          print -r mv -i -- "$file" "$dir/$base$year $album"
        fi
      done' {} +
    

( 만족스러우면 삭제하세요 print -r).

해당 방법과 perl동일한 주의 사항이 있지만 -i전달된 옵션은 데이터 손실을 방지 하는 mv데 도움이 됩니다(대신mv이동하다도착하다이사 오다대상 파일이 존재하고 디렉토리 유형인 경우).


귀하의 시도와 관련하여 :

  • sed텍스트 유틸리티이고 줄 기반이며 파일 경로에 단일 텍스트 줄은 물론 텍스트가 포함된다는 보장이 없으므로 파일 이름에 대한 파일 경로를 처리하지 않는 것이 가장 좋습니다.
  • print, 기본적으로 옵션을 허용하는 많은 구현과 마찬가지로 echo(OpenBSD의 ksh 구현에서는 그렇지 않은 것처럼 보이지만 일부는 임의 명령이 실행될 수 있음) 일부 백슬래시 이스케이프 시퀀스 확장을 수행합니다. 텍스트를 축어적으로 출력하려면(유효한 행에서 끝나도록 개행 문자 다음에), 특히 로 시작하지 않을 것이라고 보장할 수 없는 경우에는 print -r - "$text"또는 이 필요합니다 .print -r -- "$text"$text-
  • 명령( )을 따옴표 없이 바꾸면 $(...)결과에 결국 분할+glob이 적용됩니다. 네, 인용하셔도 됩니다. 중첩된 참조는 더 이상 사용되지 않는 명령 대체 형식을 사용하는 경우에만 문제가 되지만 `...`, 그럴 경우에도 가능합니다 cmd1 "`other-cmd \" $var \"`". .
  • $(...)삭제 조심하세요모두후행 개행으로 인해 일반적으로 너무 많은 항목을 제거하게 됩니다.
  • --mv그런 다음 그는 사라졌습니다.
  • mvsed파일 경로를 수정하지 않고도 호출 이 됩니다.
  • OpenBSD의 ksh 에서 for i in *현재 작업 디렉터리에 숨겨지지 않은 파일이 없으면 루프에 *파일 이름으로 경로가 계속 남게 됩니다. 일치하지 않는 파일에 대한 오류가 보고 zsh됩니다 .zmv
  • oksh glob을 사용할 때 파일 유형(예: zsh의 (#q.)=== -type f(#q/)=== -type d)에 따라 glob 확장을 제한할 수 없습니다.
  • 위의 방법과 달리 현재 작업 디렉터리의 파일 이름만 바꾸므로 각 디렉터리에서 프로세스를 반복해야 합니다.

관련 정보