쉘 스크립트에서 검색 기반 mv 이름 바꾸기가 실패합니다.

쉘 스크립트에서 검색 기반 mv 이름 바꾸기가 실패합니다.

파일 이름과 파일 일부의 이름을 바꾸는 간단한 스크립트를 만들고 싶습니다. 이 명령은 명령줄에서 제대로 실행되지만 다음과 같습니다.

find . -type f -name "*old*" -exec bash -c 'mv "$0" "${0/old/new}"' {} \; 2>&1 | grep -v "Permission denied" | grep -v "are the same file"

쉘스크립트로 다시 구현해 보았습니다.

#!/bin/bash
# renamefiles.sh - type renamefiles <old> <new>
# 
find . -type f -name "*$1*" -exec bash -c 'mv "$0" "${0/$1/$2}"' {} \; 2>&1 | grep -v "Permission denied" | grep -v "are the same file"

사용자가 입력하면,

$ renamefiles old new

오류가 발생합니다(오류 메시지 억제가 비활성화됨).

mv: './File0_old.txt' and './File0_new.txt' are the same file
mv: './Another_old_file.txt' and './Another_new_file.txt' are the same file

답변1

두 가지 가능한 해결 방법으로 시작한 다음 오류가 발생하는 이유를 설명하겠습니다.

해결책 1::

서브쉘에서 사용할 수 있도록 이 두 변수를 "임시로" 내보내십시오.

#!/bin/bash
# renamefiles.sh - type renamefiles <old> <new>

export from="$1" && export to="$2" && find . -type f -name "*$1*" -exec bash -c 'mv "$0" "${0/$from/$to}"' "{}" \; 2>&1 | grep -v "Permission denied"


exit 0

따라서 $1을 from 변수로 내보내고 $2를 to 변수로 내보냅니다. 이렇게 하면 서브쉘이 이를 읽을 수 있습니다.

해결책 2::(임시 내보내기를 좋아하지 않는 사람들이 더 간단하고 선호할 수도 있음)

#!/bin/bash
# renamefiles.sh - type renamefiles <old> <new>

find . -type f -name "*$1*" -exec bash -c 'mv "$0" "${0/$1/$2}"' "{}" "$1" "$2" \; 2>&1 | grep -v "Permission denied"

exit 0

해결책은 서브셸이 마치 스크립트 자체인 것처럼 정상적으로 액세스할 수 있도록 {}(현재 find 결과) 외부에 "$1" 및 "$2"만 전달하는 것으로 구성됩니다(예외는 bash에 전달된 -c 옵션입니다). , 첫 번째 인수는 $1 대신 $0이 됩니다. 이는 사용해 본 이후로 알 수 있는 내용인 것 같습니다.

두 솔루션에 대한 공통 사항:

  1. 항상 스크립트 끝에 종료 명령을 포함하십시오.
  2. 전달된 모든 변수({} 포함) 주위에는 따옴표가 있습니다. 이렇게 하면 공백으로 인해 변수가 잘못 해석되는 것을 방지할 수 있습니다. 나중에 스크립트가 언제 사용될지 모르기 때문에 [여기]에 공백이 있는 파일 이름이나 값이 없다고 확신하는 경우에도 이 작업을 수행하세요.

오류 원인::

오류("동일한 파일입니다")가 나타나는 이유는 매우 간단합니다.

스크립트에서 mv 명령은 주어진 파일 "$0"을 문자열 대체 결과에 의해 제공된 다른 파일("${0/$1/$2}")로 바꿉니다. 따라서 귀하의 경우 $1 및 $2는 서브셸 명령에 제공되지 않으므로 "${0//}"를 실행한 것과 같으며 아무 작업도 수행하지 않습니다. 결과적으로 이전 파일 이름과 새 파일 이름이 동일하므로 오류가 발생합니다.

관련 정보