이 작업을 올바르게 수행하는 방법
우선, 항상 변수를 인용하십시오 . 올바르게 인용하면 수행하려는 작업이 정상적으로 작동합니다.
$ pwd
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]
$ ls
pullingATerdon
일관성을 유지하기 위해 선택한 이상한 파일 이름을 유지했습니다 ( 왜 선택했는지는 모르겠습니다 ).
이제 pullingATerdon
변수 의 경로를 지정한 다음 파일을 열어 보겠습니다.
$ bacon="$(realpath pullingATerdon)"
$ echo "$bacon"
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]/pullingATerdon
$ ls $bacon
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':
예상대로 실패합니다. 그러나 이제 우리가 올바르게 인용하면 :
$ ls -l "$bacon"
-rw-r--r-- 1 terdon terdon 0 Mar 14 23:15 '/home/terdon/foo/\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]/pullingATerdon'
예상대로 작동합니다. 그리고 네, (적절한) 편집기에서 경로를 열 수도 있습니다. 제대로 emacs "$bacon"
작동합니다. 좋아, 의지 vim
와 다른 것. 불행히도 편집기 선택은 관련이 없습니다.
왜 너의 실패
실제로 사건에서 일어난 일을 추적하는 빠른 방법은을 사용하여 set -x
(다시 다시 사용 중지 set +x
) 실행하여 쉘이 실행하기 전에 실행할 각 명령을 인쇄하게합니다. 다음을 사용하여 쉘의 디버깅 메시지를 켜십시오 set -x
.
$ set -x
$ /bin/ls $bacon
+ ls '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':
그 쇼 우리 ls
의 세 가지 별도의 인수와 함께 실행 된 '/home/terdon/foo/\e[92mM@r|<'
, '+'\''|'\''|_e|\|\|0rth'
및 '[`-_-"]/pullingATerdon'
. 셸이 인용되지 않은 문자열에서 단어 분할 및 glob 확장 을 수행 하기 때문에 발생합니다 . 이 경우 쉘에서 경로의 공백을보고 각 공백으로 구분 된 문자열을 별도의 인수로 읽으므로 문제는 단어 분할입니다.
mkdir
예는 약간 차이가 있지만의 당신은 우리에게에서 오류 메시지가 표시하고 있기 때문에 두 번째 명령의 호출을. 한 번 시도한 다음 질문에 대한 출력을 얻기 위해 두 번째로 실행 한 것 같습니다. 처음 실행했을 때 다음과 같이 보일 것입니다.
$ mkdir $(realpath pullingATerdon)
++ realpath pullingATerdon
+ mkdir '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
mkdir: cannot create directory ‘[`-_-"]/pullingATerdon’: No such file or directory
다시 말하지만 단어 분리로 인해 하나가 아닌 세 개의 디렉토리를 만들려고 시도합니다. 먼저 디렉토리가 성공적으로 생성되었습니다 /home/terdon/foo/\e[92mM@r|<
.
$ ls -l /home/terdon/foo/
total 8
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|<'
drwxr-xr-x 3 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]'
그런 다음 +'|'|_e|\|\|0rth
현재 디렉토리에 디렉토리를 작성했습니다 .
$ ls -l
total 4
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:37 '+'\''|'\''|_e|\|\|0rth'
-rw-r--r-- 1 terdon terdon 0 Mar 15 00:36 pullingATerdon
그런 다음 디렉토리를 만들려고했습니다 [`-_-"]/pullingATerdon
. 이는 mkdir
기본적으로 하위 디렉토리를 만들지 않기 때문에 실패했습니다 (로 실행할 경우 가능 -p
).
$ mkdir baz/bar
mkdir: cannot create directory ‘baz/bar’: No such file or directory
당신의 인용되지 않은 문자열이 포함되어 있기 때문에 /
, mkdir
이 디렉토리의 경로가 상단 하나를 찾기 위해 시도하고, 실패로 간주.
그것이 실패한 이유이지만, 일어난 일은 더 복잡합니다. 당신이 사용 된 문자열은 실제로 쉘 글로브, 특별히이다 글로브 범위 이름이 5 자 중 하나입니다 현재 디렉토리에있는 모든 파일과 일치, `
, -
, _
또는 "
. 현재 디렉토리에 그러한 파일이 없기 때문에 glob가 아무 것도 일치하지 않으며 bash의 기본 동작과 같이 자체를 반환합니다.
$ echo "[\`-_-\"]/pullingATerdon" ## some escaping is needed here
+ echo '[`-_-"]/pullingATerdon' ## but it echoes the right thing
[`-_-"]/pullingATerdon ## and matches nothing, so returns itself.
명확히하기 위해 다음과 일치하는 glob을 제공하면 어떻게됩니까?
$ echo [p]* ## any filename starting with a p
pullingATerdon
$ echo "[p]*" ## the string "[p]*"
[p]*
따옴표없는 [p*]
파일은 일치하는 파일 이름 목록 (이 경우 하나만)으로 확장되며 이것이 전달됩니다 echo
. 당신이 모든 것을 인용해야하는 또 다른 이유.
마지막으로 표시되는 실제 오류는 명령을 두 번째로 실행할 때 발생하며 /home/terdon/foo/\e[92mM@r|<
이전 호출에서 이미 해당 디렉토리 를 작성 했기 때문에 작성하려고 할 때 첫 번째 단계에서 실패합니다 .
더 일반적으로, 임의의 파일 이름으로 작업 할 때마다 항상 쉘 글롭을 사용하십시오. 이런 것들 :
for file in *; do command "$file"; done
모든 파일 이름에 적용됩니다. 무슨 일이 있어도 위의 예에서 다음을 수행 할 수 있습니다.
emacs /home/terdon/*92mM*/pullingATerdon
대상 파일을 고유하게 식별하는 모든 glob이 수행합니다. 그렇게하면 특수 문자에 대해 걱정할 필요가 없으며 쉘이 문자를 처리하도록 할 수 있습니다.
유용한 참고 자료 :
줄 바꿈, 공백 또는 둘 다를 포함하는 파일 이름을 어떻게 찾고 안전하게 처리 할 수 있습니까? : 우수한 회색 고양이 위키에 대한 FAQ 중 하나입니다.
bash / POSIX 쉘에서 변수를 인용하는 것을 잊어 버린 보안 영향 :이 답변의 시작 부분에서 언급 한 것과 동일한 게시물. 쉘 변수를 올바르게 인용하지 않으면 잘못 될 수있는 모든 것들에 대한 훌륭하고 자세한 설명.
쉘 스크립트가 공백이나 다른 특수 문자에서 질식하는 이유는 무엇입니까? : 쉘에서 임의의 파일 이름을 처리하기 위해 알고 싶었던 모든 것.
큰 따옴표는 언제 필요합니까? : 따옴표 및 변수에 대한 자세한 내용, 특히 인용 할 필요가없는 몇 가지 경우
vim "$bacon"