Bash 스크립트에서 공백을 이스케이프 처리할 수 없는 이유는 무엇입니까? [복사]

Bash 스크립트에서 공백을 이스케이프 처리할 수 없는 이유는 무엇입니까? [복사]

Bash에서 경로의 공백 문자를 이스케이프 처리하려고 시도했지만 둘 다 작동하지 않았습니다.백슬래시또는인용 부호일하다.

.sh 스크립트:

ROOT="/home/hogar/Documents/files/"
FILE=${ROOT}"bdd.encrypted"
DESTINATION="/home/hogar/Ubuntu\ One/folder"

mv ${FILE} ${DESTINATION}

스크립트( ./file)를 실행한 후 결과는 다음과 같습니다.

mv: target 'One/folder' is not a directory

mv명령이 문자열을 분할하는 이유는 무엇 이며 이러한 일이 발생하지 않도록 하려면 어떻게 해야 합니까?

답변1

DESTINATION 변수를 확장하면 echo다음과 같은 결과를 얻을 수 있습니다.

echo ${DESTINATION}
/home/hogar/Ubuntu\ One/folder

그러나 mv이것을 이해하지 마십시오:

mv ${FILE} ${DESTINATION}                                                
mv: cannot move '/home/hogar/Documents/files/bdd.encrypted' to '/home/hogar/Ubuntu\\ One/folder': No such file or directory

(뭔가 MV가 더 길어졌네요)

이를 방지하려면 따옴표를 사용해야 합니다.

mv "${FILE}" "${DESTINATION}"

확장이 필요하지 않은 경우(이전에 이미 확장을 수행했기 때문에) "$..."다음을 사용하면 충분합니다.

mv "$FILE" "$DESTINATION"

답변2

변수를 준비하는 단계는 "충분히 가깝고" 작동하지만 이해가 부족함을 보여줍니다(그래서 게시했습니다!)

DESTINATION에 대한 할당은 다음 중 하나만 필요합니다.

DESTINATION="/home/hogar/Ubuntu One/folder"

또는

DESTINATION=/home/hogar/Ubuntu\ One/folder

큰따옴표는 따옴표를 열고(마법의 한 형태) 백슬래시는 그 뒤에 있는 단일 문자를 인용합니다. 개인적으로 큰따옴표를 사용한 형태가 시각적으로 더 좋기 때문에 더 좋다고 생각합니다.

그런데 비슷한 이유로 다음과 같이 FILE 할당을 수행합니다.

FILE="${ROOT}bdd.encrypted"

${NAME}$NAME이는 단순히 변수 이름과 그 뒤에 오는 문자를 구분하기 위해 -를 사용하는 다소 드문 경우를 보여줍니다 . 실제로 ROOT가 후행 / 없이 정의된 경우 다음과 같이 작성합니다.

FILE="$ROOT/bdd.encrypted"

더 좋아 보인다. 또한 내 경험상 언급하지 않은 몇 가지 이점도 가끔 제공합니다. 후행 슬래시는 인기 있는 것보다 인기가 없는 경향이 있으며 확실히 필요하지 않습니다. (심볼릭 링크와 관련하여 영향을 미치지만 이미 큰 답변에 비해 너무 세부적입니다.)

문제의 핵심은 실제로 다음과 같은 경우에 발생합니다.MV명령은 다음과 같이 작성되어야 합니다.

mv "$FILE" "$DESTINATION"

이제 경로를 나타내는 변수에 언제 공백이 생길지 알 수 없기 때문입니다. 간단한 변수 확장에는 괄호를 사용하지 않도록 주의하세요.

문제가 발생하는 이유는 쉘이 명령줄을 작성하는 데 사용하는 프로세스 때문입니다. 쉘 매뉴얼을 주의깊게 읽어보면 기본적으로 변수(및 기타 몇 가지 사항)가 확장된 다음 공백을 찾는다고 나와 있습니다. 물론 프로세스는 더 복잡하지만 이것이 질문의 핵심입니다.

관련되어 있고 알 가치가 있는 또 다른 사항: $*, $@"$*"의 차이점입니다 "$@". 그럼 내가 말해주지!

쉘 스크립트가 있는 경우 다음과 같이 호출할 수 있습니다.

foo -x "attached is the software" "please read the accompanying manual"

그러면 , 두 문자열은 및 로 foo표시 됩니다( 명백한 이유로 합계 로 액세스해야 함 ). 그러나 전체 매개변수 세트를 다른 스크립트에 전달하려는 경우 다음 스크립트는 모든 공간에서 끔찍한 분할로 인해 어려움을 겪게 됩니다.-x$1$2$3"$2""$3"

bar $*

다음(원본 Bourn 쉘 0.X 버전의 유일한 방법)은 모든 인수가 단일 문자열로 전달되도록 합니다(역시 잘못됨).

bar "$*"

따라서 다음 구문이 매우 특별한 경우로 추가되었습니다.

bar "$@"

의도적으로 의 개별 구성원을 $*완전한 인용 문자열로 인용하지만 구분합니다. 이제 모두가 승자입니다.

$@사용하지 않을 때 다른 효과를 실험하는 것은 약간 재미있지만 "$@"실제로는 그다지 흥미롭지 않다는 것을 곧 알게 될 것입니다. 이는 단지 주요 문제를 해결하는 특별한 경우일 뿐입니다.

배열을 지원하는 모든 최신 셸은 특별한 경우에도 @를 사용합니다.

${arr[*]}
"${arr[*]}"
"${arr[@]}"

첫 번째는 모든 공백으로 분할되어 예측할 수 없는 수의 개별 단어가 생성되고, 두 번째는 모든 배열 구성원을 하나의 문자열로 생성하며, 세 번째는 각 배열 구성원을 별도의 완전한 견적 문자열로 훌륭하게 제공합니다.

즐기다!

답변3

예, 에 값을 할당할 때 공백을 이스케이프 처리했습니다 $DESTINATION.

하지만 mv 명령과 함께 사용하면 그렇지 않습니다.

mv ${FILE} ${DESTINATION}

대신 이것을 사용하십시오:

mv "${FILE}" "${DESTINATION}"

관련 정보