Linux 시스템에 "pre_"와 같은 접두사가 붙은 파일 세트가 있는데 이를 삭제하여 모든 파일의 이름을 바꾸고 싶습니다. 이것은 내가 작성한 Perl 코드입니다. 오류는 발생하지 않지만 작업은 아직 완료되지 않았습니다.
#!/usr/bin/perl -w
my @files = `ls -1 | grep -i \"pre_.*\"`;
foreach $file ( @files )
{
my @names = split(/pre_/, $file);
my $var1 = $names[1];
'mv "$file" "$var1"';
}
답변1
당신은 아무것도 실행하지 않습니다. 작은따옴표( ) 안에 무언가를 넣으면 ''
이는 단지 문자열이므로 'mv "$file" "$var1"'
명령이 아니며 문자열이며 아무 작업도 수행하지 않습니다. 문자열 자체는 참인 진술입니다. 이 명령을 실행하려면 다음을 사용해야 합니다.
system "mv", "--", $file, $var1;
(아니요 이로 인해 명령 주입 취약점이 발생합니다.)system("mv '$file' '$var1'")
하지만 꼭 그럴 필요는 없습니다 . 다음과 perl
같은 기능을 rename()
사용하면 됩니다.
rename($file, $var1)
다음으로, 실제로 구문 분석해서는 안되는 출력은 ls
다음과 같습니다.매우 나쁜 생각이고 깨지기 쉽습니다.. 또한 Perl(또는 다른 프로그래밍 언어)에서는 전혀 필요하지 않습니다. 해당 문자열을 포함하는 현재 디렉터리의 모든 파일을 일치시키려면 pre_
(이것이 바로 grep
수행하는 작업입니다. 그럴 필요는 없지만 grep
을 사용하면 됩니다 ls -d -- *pre_*
) 다음을 사용할 수 있습니다 glob()
.
my @files = glob("*pre_*");
따라서 이 모든 것을 종합하면 다음과 같습니다.
#!/usr/bin/perl -w
use File::Glob qw(:globally :nocase);
my @files = glob("*pre_*");
foreach $file ( @files )
{
my @names = split(/pre_/i, $file);
rename($file, $names[1]);
}
그러나 그것은 정말로 좋은 생각이 아닙니다. 동일한 접두어(예: pre_file1
및 apre_file1
)를 가진 두 개의 파일이 있는 경우 첫 번째 파일은 두 번째 파일로 덮어쓰여집니다. 이 예에서는 file1
명령이 pre_
그 앞의 모든 항목을 삭제하므로 두 파일의 이름이 모두 변경됩니다. 따라서 경고를 추가하고 다음 파일을 건너뛸 수 있습니다.
#!/usr/bin/perl -w
use File::Glob qw(:globally :nocase);
my @files = glob("*pre_*");
foreach $file ( @files )
{
my @names = split(/pre_/i, $file);
if (-e $names[1]) {
warn "Warning: Not renaming '$file' to '$names[1]' " .
"because '$names[1]' exists.\n";
next;
}
rename($file, $names[1]) or
warn "rename '$file': $!\n";
}
물론 이것은 모두 바퀴를 재발명하는 것입니다. 직접 설치한 다음 perl-rename
(Debian, Ubuntu 등에서 실행 , 다른 시스템에서는 또는 apt install rename
이라고 함 ) 다음을 수행할 수 있습니다(대소문자를 구분하지 않지만 포함된 파일만 찾습니다 ).prename
perl-rename
pre_
rename -n 's/.*?pre_//si' ./*
실제 이름을 바꾸지 않고 수행할 작업만 인쇄합니다 -n
. rename
이름 바꾸기가 예상대로 작동한다고 확신하면 -n
실제로 파일 이름을 바꾸지 않고 명령을 다시 실행하십시오.
껍질이 여기를 통과합니다모두(숨겨지지 않은) 파일이며 코드에 의해 이름이 변경되지 않은 파일은 rename
무시 됩니다. 또한 in , in 을 통해 대소문자를 구분하지 않는 파일 이름만 전달하도록 셸에 지시 하거나 전역 설정 옵션을 사용할 수도 있습니다.rename
perl
pre_
./~(i)*pre_*
ksh93
./(#i)*pre_*
zsh -o extendedglob
nocaseglob
bash
zsh
yash
./*[pP][rR][eE]_*
답변2
필요한 도구가 이미 존재합니다 rename
(배포판에 따라 다름 perl-rename
) prename
.
rename 's/^pre_//' file1 file2 ...
-n
시험 실행 및 목록 이름 변경 에 사용됩니다 -v
.
rename
참고: 다르게 작동하는 명령과 혼동하지 마십시오 util-linux
.
답변3
...다른 이름 바꾸기 대안이 있습니다("바퀴를 재발명"하는 것보다) 예...
사용mmv
이와 같이:
$ mmv -n '*_*.ext' '#2.ext'
pre_file_number1.ext -> file_number1.ext
pre_file_number2.ext -> file_number2.ext
pre_file_number3.ext -> file_number3.ext
pre_file_number4.ext -> file_number4.ext
또는 Z Shell(zsh
) 내장 함수를 사용하여zmv
이와 같이:
% autoload zmv
% zmv -n '*.ext' '${f#*_}'
mv -- pre_file_number1.ext file_number1.ext
mv -- pre_file_number2.ext file_number2.ext
mv -- pre_file_number3.ext file_number3.ext
mv -- pre_file_number4.ext file_number4.ext
참고: -n
위의 두 경우 모두 안전한 시험 실행입니다. 출력이 만족스러우면 제거하거나 -v
(자세한 설명을 위해) 실제 이름 변경이 발생합니다.