10K mp4 파일 목록이 있는데 그 중 일부에는 ? 태그가 포함되어 있습니다. _(밑줄)로 바꿔야 합니다.
find 명령을 사용하여 이러한 파일을 찾을 수 있지만 이름을 바꿀 수 있는지는 확실하지 않습니다.
find . -name "*\?*.mp4" -exec mv {} XXXXXXX \;
find에서 반환된 목록을 반복해야 하고 교체해야 할 각 목록을 반복해야 하는 것 같나요? _를 사용하지만 어떻게 해야 할지 모르겠습니다.
답변1
이를 위해 사용하지 마십시오 find
. 어느 방향으로 가든 파일당 하나와 같은 것이 필요할 것입니다 find
. mv
과정이 많이 필요한데 아무 소용이 없습니다. 말할 것도 없이 그렇게 하는 것이 더 어렵습니다. 어쨌든 그건 내 의견이다.
나는 스트리밍 또는 일괄 처리 도구를 사용하며 다음을 선호하는 경향이 있습니다 pax
.
cd -P . && mkdir ../newmp4 &&
pax -rwls'|?|_|g' . "${PWD%/*}/newmp4"
디렉토리를 생성할 수 있는 경우 ../newmp4
이 작은 스크립트는 하드 링크를 사용하여 방금 생성한 디렉토리에 루트가 있는 트리를 미러링할 뿐만 아니라 .
모든 파일 이름을 밑줄로 바꿉니다.?
이렇게 하면 얻을 수 있는 이점 중 하나는둘 다이후에도 트리는 계속 존재합니다. 현재 디렉터리의 루트에 있는 파일은 영향을 받지 않습니다. 트리의 미러링된 버전에서만 변경됩니다. 따라서 삭제할 트리 버전을 결정하기 전에 결과를 확인할 수 있습니다. 절차 중에 문제가 발생하더라도 해를 끼치 지 않습니다.
그러나 이를 위해서는 하드 링크를 지원하고 최소한 +2 하위 디렉토리만큼 남은 여유 inode가 있는 파일 시스템이 필요합니다 . 단, 모든 하위 디렉토리가 동일한 파일 시스템 마운트를 공유한다고 .
가정합니다 ...
.
.
rsync
나는 그것이 그렇게 간단하다고 생각하지 않지만 실제로 동일한 효과를 얻는 것이 가능하다고 생각합니다 . 당신이 가지고 있지 않다면pax
(당신이진짜 ~해야 한다), 당신은 그것을 얻을 수 있습니다.미라빌로스유지하다(내가 아는 한)최대일반적으로 사용되는 버전리눅스 시스템에서.
답변2
개인적으로 나는 이것이 Perl의 요구 사항일 뿐이라고 생각합니다. 특수 문자 안전 및 이름 변경은 fork exec가 아닌 시스템 호출입니다.
find . -name "*\?*.mp4" -print0|perl -n0e 'next if /\?.*\//;$o=$_;s!\?!_!g;next if -e;rename $o, $_'
정의되지 않은 동작을 방지하고 이름 바꾸기 충돌을 확인하려면 ?가 있는 디렉터리의 파일을 무시하세요. 아래의 자세한 지침을 참조하세요.
find . \ # find files below the current directory
-name "*\?*.mp4" \ # having a ? in the name and ending in .mp4
-print0\ # print the file names separated by nulls
|perl \ # direct the output of find to the input of perl
-n \ # loop over standard input while assigning it to $_
-0 \ # lines from standard input are separated by null
-e \ # evaluate the next argument as perl commands
'next if /\?.*\//; # skip this file if the directory name includes ?
$o=$_; # make a copy of the file name of preserve the name
s!\?!_!g; # change the ?s in the filename to _s
next if -e; # skip file if there is a file by that name
rename $o, $_' # do the rename
답변3
내가 찾은 가장 쉬운 방법은 다른 것을 파이프로 연결하여 명령을 생성한 sed
다음 에서 명령을 실행하는 것입니다 sh
.
find . -name '*\?*.mp4' -print | sed 's/.*/"&";h;y/?/_/;x;G;s/\n/ /;s/^/mv /' | sh -s
find
에서와 같이 설명이 매우 필요 합니다 sh
. 이 sed
명령에는 설명이 필요할 수 있습니다.
s/.*/"&"/
공백이나 특수 문자를 처리하려면 입력을 큰따옴표로 묶으십시오.h
버퍼를 "보류" 버퍼에 복사하고 복사본을 저장합니다.y/?/_/
tr \? _
명령줄과 동일합니다.x
"hold" 버퍼의 내용을 모드 버퍼로 바꿉니다.G
"\n" 구분 기호를 사용하여 패턴 버퍼의 끝에 "hold" 버퍼를 추가합니다. 이제 "stringwith?\nstringwith_"가 있습니다.s/\n/ /
개행 문자를 바꾸십시오.s/^/mv /
사전 명령mv
.
그러면 이전 이름과 새 이름을 사용하여 mv
찾은 각 파일에 대한 명령이 생성 됩니다.find
답변4
그리고 zsh
:
autoload zmv # best in ~/.zshrc
zmv '(**/)(*\?*.mp4)' '$1${2//\?/_}'
이는 숨겨진 디렉터리를 제외하고 숨겨진 디렉터리 내부를 살펴보지 않습니다. 유형(일반, 디렉토리, 심볼릭 링크...)에 관계없이 이러한 파일의 이름을 바꿉니다.
파일/디렉터리 숨기기, mp4 파일 이름 바꾸기(일반 파일인 경우)만 고려하고 대소문자를 구분하지 않으려면 다음과 같습니다.
zmv '(**/)(*\?*.(#i)mp4)(#q.D)' '$1${2//\?/_}'
GNU 근사치( zmv
이전과 같이 충돌 및 재정의를 확인하지 않음):
find . -iname '*\?*.mp4' -type f -exec bash -c '
for file do
base=${file##*/}
mv -i "$file" "${file%/*}/${base//\?/_}"
done' {} +