여러 파일 이름의 일부를 소문자로 바꾸려고하면 이름 바꾸기가 "허용되지 않음"을 반환합니다.


12

Ubuntu 16.04의 폴더에 두 개의 파일이 있습니다.

a1.dat
b1.DAT

나는 이름을 바꿀 b1.DATb1.dat나는 폴더에 결과 파일을 다음과 같은 것 때문에 :

a1.dat
b1.dat

나는 (성공하지 못했습니다) :

$ rename *.DAT *.dat
Bareword "b1" not allowed while "strict subs" in use at (user-supplied code).
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).

$ find . -iname "*.DAT" -exec rename DAT dat '{}' \;
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).

이것을 검색하면 의미있는 해결책이 없었습니다 ...


또한 mmv
PlasmaHH

답변:


14

이 오류는 Perl에서 온 것처럼 보입니다 rename. 인용 부호를 사용해야하지만 변경하려는 부분, 검색 및 교체 스타일 만 지정하면됩니다. 구문은 다음과 같습니다.

rename -n 's/\.DAT/\.dat/' *

-n실제로 파일 이름을 바꾸려면 테스트 후 제거하십시오 .

숨겨진 파일을 포함 시키려면 명령을 실행하기 전에 glob 설정을 변경하십시오.

shopt -s dotglob

재귀 적으로 파일 이름을 바꾸려면 다음을 사용할 수 있습니다.

shopt -s globstar
rename -n 's/\.DAT/\.dat/' **

또는 현재 디렉토리에 또는로 끝나지 않는 경로가 많은 경우 .DAT두 번째 명령에서 해당 경로를 지정하는 것이 좋습니다.

rename -n 's/\.DAT/\.dat/' **/*.DAT

파일의 다양한 이름이 끝나지 않으면 더 빠릅니다 .DAT. [1]

이러한 설정을 끄려면 shopt -u예를 들어을 사용할 수 shopt -u globstar있지만 기본적으로 해제되어 있으며 새 쉘을 열면 해제됩니다.

이로 인해 인수 목록이 너무 길면 다음과 같이 사용할 수 있습니다 find.

find -type f -name "*.DAT" -exec rename -n -- 's/\.DAT/\.dat/' {} \;

또는 더 나은

find -type f -name "*.DAT" -exec rename -n -- 's/\.DAT/\.dat/' {} +

찾은 파일에서 인수 목록을 구성하므로 find ... -execwith를 사용 하는 +것이 사용 하는 것보다 빠릅니다 \;. 원래 나는 당신이 argument list too long문제 가 있다고 언급했기 때문에 그것을 사용할 수는 없다고 생각 했지만, 이제는 그 문제를 피하기 위해 필요에 따라 목록이 명령을 여러 번 호출하여 똑똑하게 나눌 것임을 알고 있습니다. [2] .

rename모든 파일 이름을 동일한 방식으로 처리 하므로 인수 목록이 여러 호출에서 안전하게 분리 될 수 있으므로 인수 목록의 길이는 중요하지 않습니다. 함께 사용하는 명령이 -exec여러 인수를 허용하지 않거나 인수가 특정 순서로되어 있거나 다른 이유로 인수 목록을 분리하면 원하지 않는 일 \;이 발생하는 경우을 사용하면 명령이 한 번만 호출됩니다. 발견 된 모든 파일에 대해 (인수 목록이 다른 방법으로 너무 길면 시간이 오래 걸립니다!).


이 답변을 개선 할 수있는 매우 유용한 제안에 대해 Eliah Kagan 에게 감사드립니다 .

[1] globbing 할 때 파일 이름 지정 .
[2] 는 인수 목록 find ... -exec+분할합니다 .


감사. 재귀 적으로 수행하는 방법 (모든 하위 폴더의 모든 파일에 대해)?
Samo

@Samo 내 편집보기 :)
Zanna

작동하지 않습니다 : $ rename 's / \. DAT / \. dat /'** bash : / usr / bin / rename : 인수 목록이 너무 깁니다
Samo

1
@Samo 당신은 -n테스트 후 이름 바꾸기에서 제거해야합니다 -변경 내용을 보여주기 위해
Zanna

1
Centos 및 Arch에서 이름 바꾸기에이 동작이 나타나지 않습니다. WSL에서 데비안을 사용하여 여기에 도착했습니다. 이 구문은 효과가있었습니다.
xtian

6

넌 할 수있어:

rename -n 's/DAT$/\L$&/' *.DAT

-n실제로 이름을 바꾸려면 삭제하십시오 .

  • glob 패턴 은 현재 디렉토리 *.DAT.DAT있는 모든 파일과 일치합니다.

  • 에서 rename의 대체, DAT$경기 DAT

  • \L$&전체 일치를 소문자로 만듭니다. $&전체 경기를 말합니다

당신이 원하는 경우 b1.DAT:

rename -n 's/DAT$/\L$&/' b1.DAT

예:

% rename -n 's/DAT$/\L$&/' *.DAT
rename(b1.DAT, b1.dat)

4

다른 답변 은이 질문의 두 가지 주요 측면 중 하나를 설명했습니다. 필요한 이름 바꾸기 작업을 성공적으로 수행하는 방법입니다. 이 답변의 목적은 명령 컨텍스트에서 이상한 "허용되지 않은"오류 메시지의 의미를 포함하여 명령이 작동하지 않은 이유를 설명하는 것 rename입니다.

이 답변의 첫 번째 섹션은 renamePerl과 의 관계 및 rename전달하는 첫 번째 명령 행 인수 (코드 인수)를 사용하는 방법에 관한 것입니다. 두 번째 섹션은 쉘이 인수 목록을 구성하기 위해 확장 (특히 globbing)을 수행하는 방법에 관한 것입니다. 세 번째 섹션은 "Bareword not allowed"오류를 발생시키는 Perl 코드에서 수행되는 작업에 관한 것입니다. 마지막으로, 네 번째 섹션은 명령 입력과 오류 발생 사이에 발생하는 모든 단계를 요약 한 것입니다.

1. rename이상한 오류 메시지가 나타나면 "Perl"을 검색에 추가하십시오.

데비안과 우분투에서이 rename명령은 파일 이름 바꾸기를 수행 하는 Perl 스크립트입니다. 이 글을 쓰는 시점에서 여전히 지원되는 14.04 LTS를 포함한 이전 릴리스 에서는 명령 을 가리키는 ( 직접적으로 ) 심볼릭 링크 였습니다 . 최신 릴리스에서는 최신 명령 을 가리 킵니다 . 이 두 Perl 이름 바꾸기 명령 은 대부분 같은 방식으로 작동하며이 답변의 나머지 부분에 대해 두 가지를 모두 언급하겠습니다 .prenamefile-renamerename

rename명령 을 사용하면 다른 사람이 작성한 Perl 코드 만 실행하는 것이 아닙니다. 또한 자신의 Perl 코드를 작성 rename하고 실행하도록 지시하고 있습니다. 때문이다 첫 번째 명령 줄 인수 당신이에 전달 rename이외의 명령, 옵션 인수 등은 -n, 실제 펄 코드로 구성된다 . 이 rename명령은이 코드를 사용 하여 이후의 명령 줄 인수로 전달한 각 경로 이름 에서 작동합니다 . (경로 이름 인수를 전달하지 않으면 표준 입력 에서 한 줄에 하나씩 rename경로 이름 을 읽습니다 .)

코드는 loop 내부 에서 실행 되며 경로 이름마다 한 번씩 반복 됩니다. 루프가 반복 될 때마다 코드가 실행되기 전에 특수 $_변수 에 현재 처리중인 경로 이름이 할당됩니다. 코드로 인해 값이 $_다른 것으로 변경되면 해당 파일의 이름이 새 이름으로 바뀝니다.

Perl의 많은 표현식$_피연산자 로 사용할 다른 표현식이없는 경우 변수 에 대해 내재적으로 작동합니다 . 예를 들어, 대체 표현식 은 변수 가 보유한 문자열에서 $str =~ s/foo/bar/첫 번째 항목을 foo로 변경하거나을 포함하지 않으면 변경되지 않은 상태로 둡니다 . 방금 작성하는 경우 명시 적으로 사용하지 않고 연산자를 , 그것은에 운영 . 이것은 짧다 .$str barfoos/foo/bar/=~$_s/foo/bar/$_ =~ s/foo/bar/

표현식 을 코드 인수 (즉, 첫 번째 명령 행 인수) 로 전달 하는s/// 것이 일반적 rename이지만 반드시 그럴 필요는 없습니다. 루프 내에서 실행될 Perl 코드를 제공하여 각 값을 검사 $_하고 조건부로 수정할 수 있습니다.

이것은 시원하고 유용한 결과 가 많이 있지만, 대부분은이 질문과 답변의 범위를 벗어납니다. 내가 이것을 여기에 가져온 주된 이유-사실이 대답을 게시하기로 결정한 주된 이유는-첫 번째 인수 rename가 실제로 Perl 코드 이기 때문에 이상한 오류 메시지가 표시되고 검색을 통해 정보를 찾는 데 어려움이있는 경우 검색 문자열에 "Perl"을 추가하거나 "rename"을 "Perl"로 바꾸는 경우가 종종 있습니다.

2.와 rename *.DAT *.datrename명령은 본 적이 *.DAT!

같은 명령은 rename s/foo/bar/ *.txt일반적으로 통과하지 않는 *.txt받는 명령 줄 인수로 rename프로그램, 그리고 당신이 그것을하고 싶지 않아 , 당신은 이름이 그대로있는 파일이 없으면 *.txt희망 당신은하지 않습니다.

rename해석하지 않습니다 글로브 패턴이 좋아 *.txt, *.DAT, *.dat, x*, *y, 또는 *경로 이름 인수로 전달합니다. 대신, 쉘은 경로 확장수행 합니다 (파일 이름 확장이라고도하며 글 로빙이라고도 함). 이것은 rename유틸리티가 실행 되기 전에 발생 합니다. 쉘은 글롭을 잠재적으로 여러 경로 이름으로 확장하여 별도의 명령 행 인수로에 모두 전달합니다 rename. 우분투에서 대화 형 쉘은 변경하지 않는 한 Bash 이므로 위 의 Bash 참조 매뉴얼에 링크했습니다 .

glob 패턴이 확장되지 않은 단일 명령 행 인수로 전달 될 수있는 상황이 하나 rename있습니다. 파일과 일치하지 않는 경우입니다. 이 상황에서 다른 쉘은 다른 기본 동작을 나타내지 만 Bash의 기본 동작은 단순히 글로브를 단순히 통과시키는 것입니다. 그러나 당신은 이것을 거의 원하지 않습니다! 원하는 경우 패턴을 인용 하여 패턴이 확장되지 않았 는지 확인 해야 합니다. 이것은뿐만 아니라 모든 명령에 인수를 전달합니다 .rename

인용 부호는 글 로빙 (파일명 확장)을위한 것이 아닙니다. 쉘이 인용되지 않은 텍스트에 대해 수행하는 다른 확장 이 있고, 일부에 대해서는 인용 부호로 묶인 텍스트에 대해서도 확장 이 있기 때문 " "입니다. 일반적으로 공백을 포함하여 쉘에서 특수하게 처리 할 수있는 문자가 포함 된 인수를 전달하려면 항상 따옴표로 인용해야 ' '합니다 .

Perl 코드 s/foo/bar/에는 쉘에서 특별히 다루는 것이 포함되어 있지 않지만 인용하고 작성하는 것이 좋을 것입니다 's/foo/bar/'. (사실, 내가 한 유일한 이유는 없습니다 아직 인용에 대해 이야기하지 않았다대로, 일부 독자들에게 혼동 될 것이 었습니다.) 그 이유는 내가 펄 코드는 매우 일반적이기 때문에이되었을 것이다 좋은 말할 않습니다 포함 이러한 문자를 사용하고 해당 코드를 변경하려는 경우 인용이 필요한지 확인하지 못할 수 있습니다. 반대로, 쉘이 glob를 확장하도록하려면 인용 되지 않아야 합니다.

3. Perl 인터프리터가 "허용되지 않음"이라는 의미

질문에 표시된 오류 메시지는을 실행할 때 rename *.DAT *.dat*.DAT이 하나 이상의 파일 이름 목록으로 확장 되었으며 해당 파일 이름 중 첫 번째 파일 이름이 임을 나타 b1.DAT냅니다. 이후의 모든 인수는 다른 인수에서 *.DAT확장 *.dat되거나 확장 된 이후 모두 해당 인수 뒤에 오기 때문에 경로 이름으로 해석됩니다.

실제로 실행 된 것은와 같았고 옵션이 아닌 첫 번째 인수를 Perl 코드로 취급 rename b1.DAT ...하기 때문에 rename질문은 다음 b1.DAT과 같이됩니다. Perl 코드로 실행할 때 "허용되지 않는"오류 가 발생하는 이유는 무엇입니까?

Bareword "b1" not allowed while "strict subs" in use at (user-supplied code).
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).

쉘에서 우리는 다른 문자열로 자동 변환하는 의도하지 않은 쉘 확장 으로부터 문자열 을 보호하기 위해 문자열 인용 합니다 (위 섹션 참조). 쉘은 범용 언어와는 매우 다르게 작동하는 특수 목적의 프로그래밍 언어 이며 매우 이상한 구문과 의미가이를 반영합니다. 그러나 Perl은 범용 프로그래밍 언어 이며, 대부분의 범용 프로그래밍 언어 와 마찬가지로 Perl에서 인용하는 주된 목적은 문자열 을 보호하는 것이 아니라 전혀 언급하는 것입니다. 이것은 실제로 대부분의 프로그래밍 언어가 자연 언어 와 유사한 방식 입니다. 영어로, 개가 있다고 가정하면, "개"는 두 단어로 된 반면, 개는 개입니다. 마찬가지로 Perl에서 '$foo'문자열 $foo은 이름이지만 이름은 $foo입니다.

그러나 거의 모든 다른 범용 프로그래밍 언어와는 달리, 펄 것 또한 때때로으로 인용되지 않은 텍스트를 해석 언급 이 동일한 문자로 구성되어 있다는 점에서, 그것과 "동일한"인 문자열을 - 문자열을 같은 순서. 코드가 간결한 경우 ( $또는 다른 sigil이 없거나 아래 참조) 코드를 해석하려고 시도하고 다른 의미를 찾지 못하면 코드를 해석하려고 시도 합니다. 그런 다음 제한 을 활성화하여 알리지 않는 한 문자열로 사용합니다 .

Perl의 변수는 일반적으로 변수 의 넓은 유형을 지정 하는 sigil 이라는 문장 부호 문자로 시작 합니다. 예를 들어, $수단 스칼라 , @수단 배열%수단 해시 . ( 다른 사람이 있습니다. ) 당신이 혼란 (또는 지루한) 찾을 경우 어떻게하지 걱정, 난 단지 말을 꺼내는거야 때문 유효한 이름 펄 프로그램에서 나타나지만가되어 있지 시길 앞에, 그 이름 간결한 것으로 알려져 있습니다 .

Bareword는 다양한 용도로 사용되지만 일반적으로 프로그램 (또는 프로그램에서 사용하는 모듈)에 정의 된 내장 기능 또는 사용자 정의 서브 루틴 을 나타냅니다 . 펄은 더 호출되는 함수 내장 없다 b1또는 DAT펄 인터프리터 코드를 볼 때, b1.DAT그것은 치료를 시도 b1하고 DAT서브 루틴의 이름으로. 이러한 서브 루틴이 정의되어 있지 않으면 실패합니다. 그런 다음 제한 사항 이 사용 가능하지 않으면이를 제한 조건 으로 문자열로 취급합니다. 실제로 이것이 의도 했는지 여부 는 누구나 추측 할 수 있지만 이것은 효과가 있습니다 . Perl의 .연산자는 문자열을 연결 하므로 문자열b1.DAT평가됩니다.b1DAT. 즉, 나 b1.DAT같은 것을 쓰는 나쁜 방법 입니다.'b1' . 'DAT'"b1" . "DAT"

perl -E 'say b1.DAT'짧은 Perl 스크립트 say b1.DAT를 Perl 인터프리터로 전달 하는 명령을 실행하여이를 직접 테스트하여 실행할 수 있습니다 b1DAT. (이 명령에서 ' '따옴표를 통과 쉘에게 say b1.DAT하나의 명령 줄 인수로, 그렇지 않으면 공간을 야기 say하고 b1.DAT하는 별도의 단어로 분석 하고 perl별도의 인수로받을 것입니다. perl않습니다 하지 따옴표 자체를 참조로 쉘이 제거합니다 .)

그러나 이제use strict; Perl 스크립트를 작성해보십시오say . 이제는 같은 종류의 오류로 실패합니다 rename.

$ perl -E 'use strict; say b1.DAT'
Bareword "b1" not allowed while "strict subs" in use at -e line 1.
Bareword "DAT" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.

이것은 use strict;Perl 인터프리터가 베어 워드를 문자열로 취급하는 것을 금지 했기 때문에 발생했습니다 . 이 특정 기능을 금지하려면 subs제한 을 설정하는 것만으로도 충분합니다 . 이 명령은 위와 동일한 오류를 생성합니다.

perl -E 'use strict "subs"; say b1.DAT'

그러나 일반적으로 Perl 프로그래머는 단지 쓰기 만 use strict;subs것입니다. use strict;일반적으로 권장되는 방법입니다. 따라서 rename명령은 코드에 대해이 작업을 수행 합니다 . 그렇기 때문에 오류 메시지가 나타납니다.

4. 요약하면 다음과 같습니다.

  1. b1.DAT은 첫 번째 명령 줄 인수로 전달 되었으며, rename각 경로 이름 인수에 대해 루프에서 실행되는 Perl 코드로 처리되었습니다.
  2. 이것은 운영자 를 의미 b1하고 DAT연결하는 것으로 .간주되었습니다.
  3. b1DATsigils로 시작하지 않았다, 그래서 그들은 barewords으로 처리 하였다.
  4. 이 두 개의 베어 워드는 내장 함수 또는 사용자 정의 서브 루틴의 이름으로 사용되었지만 그러한 이름은 없었습니다.
  5. "strict subs"가 활성화되어 있지 않으면 문자열 표현식처럼 취급 'b1'되고 'DAT'연결됩니다. 의도 한 것과는 거리가 멀기 때문에이 기능이 종종 도움이되지 않는 방법을 보여줍니다.
  6. 때문에 그러나 "엄격한 잠수정은"활성화 된 rename모든 수 제한 ( vars, refs, 및 subs). 따라서 대신 오류가 발생했습니다.
  7. rename이 오류로 인해 종료하십시오. 이러한 종류의 오류는 일찍 발생했기 때문에 통과하지 않아도 파일 이름 바꾸기 시도가 수행되지 않았습니다 -n. 이것은 의도하지 않은 파일 이름 변경과 때로는 실제 데이터 손실로부터 사용자를 보호하는 좋은 방법입니다.

Zanna 에게 감사의 말을 전한다 . 이 답변을보다 초안으로 작성하여 몇 가지 중요한 단점을 해결하도록 도와주었습니다 . 그녀가 없었다면이 대답은 의미가 떨어졌을 것이며 전혀 게시되지 않았을 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.