공백과 특수 문자가 포함된 cp는 터미널에서는 잘 작동하지만 스크립트에서는 작동하지 않습니다.

공백과 특수 문자가 포함된 cp는 터미널에서는 잘 작동하지만 스크립트에서는 작동하지 않습니다.

파일을 찾아 특정 폴더에 복사하는 스크립트를 작성하려고 합니다. 파일 이름에는 공백 및 기타 특수 문자가 포함되어 있습니다.

a=$(ls ~/Downloads/ | grep $1)
a="'$a'"
a="~/Downloads/"$a
echo $a
cp $a ~/Documents/books/.

파일 이름을 인용하면 터미널에서 제대로 작동합니다. 그러나 스크립트에서는 단어가 별도의 인수로 처리됩니다. 위 스크립트에서 $a가 에코되면 다음과 같은 내용이 표시됩니다.

~/Downloads/'Ian Goodfellow, Yoshua Bengio, Aaron Courville - Deep Learning [pre-pub version] (2016, MIT Press).pdf'

파일명이 인용되어 있는 것을 볼 수 있습니다. 위의 인수가 터미널의 cp에 전달되면 제대로 작동하지만 스크립트에서는 작동하지 않습니다. 도와주세요.

답변1

~/Downloads특정 파일을 에서 로 복사하려는 것 같습니다 ~/Documents/books.

가장 먼저 주목해야 할 점은 ~변수로 동작하지 않는다는 것입니다. 특히, 그렇습니다~ 아니다인용된 경우 홈 디렉터리의 경로를 확장합니다. 따라서 스크립트에서는 $HOME홈 디렉터리를 참조하는 데 사용하는 것이 더 좋습니다 .

두 번째는 변수 값에 리터럴 작은따옴표를 추가하는 것 같습니다 $a. 이는 필요하지 않으며 "해당 파일이나 디렉터리가 없습니다" 오류만 발생합니다(파일 이름에 작은따옴표가 없기 때문입니다).

ls세 번째는 스크립트에서 사용을 피해야 한다는 것입니다 . 예를 들어 이 경우에는 $1단순히 파일 이름만 있으면 ~/Downloads검색할 필요가 전혀 없습니다. 또한 다음과 같은 grep $1여러 가지 이유로 사용에 문제가 있습니다.

  • grep주로 텍스트에 사용됩니다.서류. 파일 이름은 이론적으로 개행 문자를 포함할 수 있습니다. 따라서 "grepping" 파일 이름은 이름이 "nice"라는 것을 아는 경우에만 작동합니다.
  • $1따옴표가 없으므로 grep공백이나 기타 특수 문자가 포함되어 있으면 혼동될 수 있습니다. 예를 들어 $1is 인 경우 *현재 디렉터리의 모든 파일 이름으로 확장됩니다.
  • 문자열이 $1대시로 시작하면 에 대한 옵션으로 간주됩니다 grep.

따라서 스크립트는 다음과 같이 작성될 수 있습니다.

#!/bin/sh

name="$HOME/Downloads/$1"

printf 'The filename is "%s"\n' "$name"

cp "$name" "$HOME/Documents/books"

여기서 명령 printf은 선택한 파일의 이름을 출력하는 것입니다. 나는출력 중이름 주위에 큰따옴표가 있지만 이름은 그렇습니다.~ 아니다거기에 큰 따옴표가 있습니다. 대신 마지막 줄에 $name호출 을 인용하겠습니다 . cp사실 제가 꼭 인용하고 있는 건모두내가 아는 확장으로 인해 쉘이 변수 값을 분할하게 될 것입니다.

해당 스크립트를 다음과 같이 사용합니다.

./script.sh 'Ian Goodfellow, Yoshua Bengio, Aaron Courville - Deep Learning [pre-pub version] (2016, MIT Press).pdf'

파일 이름에는 셸에서 특수한 공백과 문자가 포함되어 있으므로 파일 이름을 따옴표로 묶어야 합니다.

스크립트에서 명령줄에 제공된 단어가 포함된 파일을 찾도록 하려면 다음과 같이 말할 수 있습니다.

./script.sh Goodfellow

그런 다음 주어진 문자열을 globbing 패턴으로 사용합니다.

#!/bin/sh

for name in "$HOME/Downloads"/*"$1"*.pdf; do
    printf 'Will copy the file "%s"\n' "$name"
    cp "$name" "$HOME/Documents/books"
done

이제 스크립트는 첫 번째 인수를 사용하여 파일 이름에 지정된 문자열이 포함 된 모든 .pdf파일을 반복합니다. ~/Downloads이러한 각 파일은 에 복사됩니다 ~/Documents/books.

파일을 장황하게 복사하는 Unix를 사용하는 경우 cp -v스크립트가 더 축소될 수 있습니다.

#!/bin/sh

cp -v "$HOME/Downloads"/*"$1"*.pdf "$HOME/Documents/books"

이렇게 하면 지정된 패턴과 일치하는 파일 이름을 더 이상 반복하지 않으므로 사용자가 직접 출력 형식을 지정하는 것을 방지할 수 있습니다("Will copy ..."). 대신 우리는 여러 파일 이름을 지정하면 cp(그리고 globbing 패턴이 여러 파일 이름으로 확장될 수 있음) 단일 명령을 사용하여 일부 대상 디렉터리에 복사할 수 있다는 사실에 의존합니다 .


또한보십시오:

관련 정보