.png)
파일에서 아포스트로피를 제거해야 합니다. 나는 여러 가지 접근 방식을 시도했습니다.스택 교환.
저는 Synology NAS를 사용하고 있어서 Python이나 Perl이 없고 특정 디렉터리를 제외해야 합니다(find -prune).
다음 find 명령은 테스트 중에 일반적으로 작동하는 것 같습니다(에코 사용).
find . -depth \( -type d -name "@*" -o -name "*#recycle*" -o -name "*SynoResource*" -prune \) -o \( -name "*\'*" -execdir bash -c 'for f; do echo mv ${f/\\\'/\\\\'} `echo $f | sed 's/\\\'/X/g'`; done' _ {} + \)
"911's.zip"과 같은 파일의 경우 아포스트로피 '를 X로 바꾸면 다음이 생성됩니다(위 명령 사용).
mv ./911's.zip ./911Xs.zip
명령을 실행하기 위해 "echo"를 제거하면 다음 오류가 발생합니다.
mv: target '911Xs.zip' is not a directory
대화형 셸에서는 다음을 사용하여 파일 이름을 바꿀 수 있습니다.
mv 911\'s.zip 911Xs.zip
물론 '( 와 같은 \'s가 여러 개 있는 경우에도 ${f/\'/X}
) 탈출을 시도했지만 작동하지 않았습니다.
어떤 아이디어가 있나요?
감사합니다,
게리
답변1
몇 가지 문제:
- 프로세스가 먼저 떠나기 때문에
-prune
결합 할 수 없으므로 디렉토리의 전체 내용이 처리된 후에는 너무 늦어서 아무런 효과가 없습니다.-depth
-depth
-prune
- 당신의
-prune
위치가 잘못되었습니다. 어디에 넣으면 일치하는 파일에만 적용됩니다-name "*SynoResource*"
. 동일 합니다.-type d
에만 적용됩니다-name "@*"
. - 매개변수 확장 및 명령 대체에 큰따옴표가 누락되어 분할+글로브가 발생합니다.
echo
일반적으로 임의의 데이터를 출력하는 데 사용할 수 없습니다.'
내부에 작은따옴표 문자열이 있을 수 없습니다 .'
리터럴 값을 명령에 전달 해야 하는 경우 다른 셸 인용 연산자("..."
또는 백슬래시)를 사용하고 작은따옴표 밖에서 인용해야 합니다.'
그것은 그들에게 특별한 것이 아니며mv
, 그것을 피할 필요도 없습니다. 이는 쉘에만 특별하며 강력한 참조 연산자입니다.sed
find
$(...)
더 이상 사용되지 않는 대신 사용해야 합니다`...`
(백슬래시가 포함될 경우 더 복잡해집니다).
그래서 여기 있습니다:
LC_ALL=C Q="'" find . -depth \
! -path '*/@*' \
! -path '*#recycle*' \
! -path '*SynoResource*' \
-name "*'*" -execdir bash -c '
for file do
mv -i -- "$file" "${file//$Q/X}"
done' bash {} +
여기서는 -prune
에서 작동하지 않기 때문에 ( GNU에서도 호출됨 ) -depth
을 사용하여 전체 경로를 기반으로 제외된 디렉터리의 파일을 필터링합니다. 그러나 이는 성능 관점에서 이상적이지 않은 디렉터리로 이동한다는 의미입니다.-path
-wholename
find
find
를 사용한다는 것은 기본 이름만 바꾸면 괜찮다는 것을 의미하지만, s가 있는 파일이 포함된 모든 디렉터리 에서 최소한 하나를 실행 -execdir
하게 된다는 의미이기도 합니다 . 또는 다음을 수행할 수 있습니다.bash
'
LC_ALL=C Q="'" find . -depth \
! -path '*/@*' \
! -path '*#recycle*' \
! -path '*SynoResource*' \
-name "*'*" -exec bash -c '
for file do
dir=${file%/*} base=${file##*/}
mv -i -- "$file" "$dir/${base//$Q/X}"
done' bash {} +
이렇게 하면 스크립트가 실행되는 동안 누군가가 파일과 디렉터리의 이름을 바꾸는 것에 대해 더 효율적이기는 하지만 덜 안전합니다.
연습 실행의 경우 mv
명령을 다음으로 바꿀 수 있습니다.
(PS4="Would run"; set -x; : mv -- "$file" "$dir/${base//$Q/X}")
echo
bash
이는 추적 출력에서 모호하지 않게 하기 위해 필요한 곳에 따옴표를 사용하기 때문에 as를 사용하는 것보다 낫습니다 . 추적 출력은 동일한 명령을 실행하는 데 사용할 수 있는 유효한 쉘 코드처럼 보입니다.
여기에서 -exec
바꾸기를 사용하면 -execdir
이름이 바뀔 파일을 명확하게 추적할 수도 있습니다.
디렉터리 깊이를 먼저 사용하되 계속 처리하려면 출력에서 -prune
GNU(및 사용 가능한 경우 GNU)를 사용하여 이를 반전시키는 또 다른 방법이 있습니다.tac -s ''
xargs
find -print0
LC_ALL=C find . -depth \
'(' -name '@*' -o \
-name '*#recycle*' -o \
-name '*SynoResource*' \
')' -type d -prune -o \
-name "*'*" -print0 |
tac -s '' |
Q="'" xargs -r0 bash -c '
for file do
dir=${file%/*} base=${file##*/}
mv -i -- "$file" "$dir/${base//$Q/X}"
done' bash {} +
GNU는 없지만 bash가 tac
4.4 xargs
이상인 경우 다음을 수행할 수도 있습니다.
LC_ALL=C find . -depth \
'(' -name '@*' -o \
-name '*#recycle*' -o \
-name '*SynoResource*' \
')' -type d -prune -o \
-name "*'*" -print0 |
Q="'" bash -c '
readarray -td "" files &&
for (( i = ${#files[@]} - 1; i >= 0; i-- )); do
file=${files[i]}
dir=${file%/*} base=${file##*/}
mv -i -- "$file" "$dir/${base//$Q/X}"
done' bash {} +
(아직 테스트해본 적은 없으니 참고해주세요.)