realpath 또는 readlink에 의해 반환 된 절대 경로를 어떻게 위생 처리하거나 이스케이프 처리 할 수 ​​있습니까?


9

realpathreadlink절대 경로를 반환 :

+akiva@X230:~$ realpath ZannaIsAwesome
/home/akiva/ZannaIsAwesome

그런 길은 다루기 쉽다. 그러나 이와 같은 문제에는 몇 가지 문제가 있습니다.

여기에 이미지 설명을 입력하십시오

예를 들어 :

여기에 이미지 설명을 입력하십시오

따라서 이와 같은 이름은 다른 명령에 제공 할 수 있도록 소독해야합니다. 유스 케이스는 다음과 같습니다.

+a@X230:~/\e[92mM@r|< $hu+'|'|_e|\|\|0rth [`-_-"]$ bacon=$(realpath pullingATerdon)
+a@X230:~$ vim $bacon 

말할 것도없이 vim $bacon예상대로 작동하지 않습니다.

절대 경로를 삭제하여 다른 명령과 작동하도록하려면 어떻게해야합니까?


3
항상 변수를 인용하십시오 :vim "$bacon"
steeldriver

@steeldriver 왜 그렇습니까?
Akiva

3
그렇지 않은 경우 다음과 같은 상황에 처하게됩니다.
terdon

답변:


12

이 작업을 올바르게 수행하는 방법

우선, 항상 변수를 인용하십시오 . 올바르게 인용하면 수행하려는 작업이 정상적으로 작동합니다.

$ 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이 수행합니다. 그렇게하면 특수 문자에 대해 걱정할 필요가 없으며 쉘이 문자를 처리하도록 할 수 있습니다.


유용한 참고 자료 :

  1. 줄 바꿈, 공백 또는 둘 다를 포함하는 파일 이름을 어떻게 찾고 안전하게 처리 할 수 ​​있습니까? : 우수한 회색 고양이 위키에 대한 FAQ 중 하나입니다.

  2. bash / POSIX 쉘에서 변수를 인용하는 것을 잊어 버린 보안 영향 :이 답변의 시작 부분에서 언급 한 것과 동일한 게시물. 쉘 변수를 올바르게 인용하지 않으면 잘못 될 수있는 모든 것들에 대한 훌륭하고 자세한 설명.

  3. 쉘 스크립트가 공백이나 다른 특수 문자에서 질식하는 이유는 무엇입니까? : 쉘에서 임의의 파일 이름을 처리하기 위해 알고 싶었던 모든 것.

  4. 큰 따옴표는 언제 필요합니까? : 따옴표 및 변수에 대한 자세한 내용, 특히 인용 할 필요가없는 몇 가지 경우

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.