2014-02-07 3 views
3

이러한'아이덴티티 '기능 (/ 복귀 전달 인자에 대하여)에'아이덴티티 '함수를 작성하는 것 '함수 :이 가능 다음 2 개 특성을 만족하여야

argv_count() { echo "argv_count('[email protected]'):$#"; } 
argv_count $(identity a\ b c\ d) 
# (Expected output:) 
# argv_count('a b c d'):2 

추가 인용문이 필요할 경우 도입 될 수 있습니다. 다음과 같은

간단한 후보 번째 테스트 불합격 : 그것은 표준 입력 항등 함수 상대적으로

identity() { for arg in "[email protected]"; do echo "$arg"; done; } 

고양이는 정확한 해결책이 아니다 | 표준 출력이.

답변

6

아니요, 불가능합니다. 그 이유는 쉘이 명령 대체 (즉, $(somecommand))의 출력을 구문 분석 할 때 단어 분할 및 와일드 카드 확장 을 수행하지만 인용 부호 또는 이스케이프 평가을 수행하지 않기 때문입니다. 즉, identity의 출력에 공백이 포함되어있는 경우 쉘 은이를 피하기 위해 추가 한 내용에 상관없이 "단어"(즉 다른 프로그램의 인수) 사이의 구분자로 간주합니다. 더욱이 출력물에있는 임의의 와일드 카드를 포함하는 단어 이 일치하는 파일 목록 (있는 경우)으로 확장됩니다. 즉, $(identity 'foo * bar')이 실패하면 이중 운명이 정해진 것입니다.

위와 같이 쉘 설정을 변경하여 위조 된 것으로 분류 할 수있는 방법이 있습니다. 예를 들어, set -f은 와일드 카드 확장을 해제하여 문제를 해결합니다. 단, identity을 실행하기 전에 상위 쉘에서 설정해야합니다. 그런 다음 나중에 다시 정상으로 설정하거나 다른 많은 작업이 중단됩니다. 마찬가지로 IFS를 변경하여 공백을 분리 기호로 취급하지 못하도록 할 수 있습니다. 그러나 다시 부모 셸에서이 단어를 변경하고 나중에 다시 설정해야합니다. 대체 문자가 무엇이든지간에 문제를 일으킬 수 있습니다. 너는 선택했다. 그래서 당신은 그것을 가짜로 만들 수는 있지만 꽤 나쁜 놈입니다.

EDIT : Michael Kropat이 지적했듯이 eval을 사용하면 "fake"하는 또 다른 방법이며 조심스럽게 수행하면 유연성이 향상됩니다.

+0

감사 :

$ argv_count a\ b c\ d argv_count('a b c d'):2 $ identity() { printf ' %q' "[email protected]"; } $ eval argv_count "$(identity a\ b c\ d)" argv_count('a b c d'):2 $ eval argv_count "$(eval identity "$(identity a\ b c\ d)")" argv_count('a b c d'):2 

또는 고든 데이비슨의 까다 케이스 그 설명! 실용적인 맥락에서이를 대체하려면 : 어떤 기능도 파일 이름 목록 (공백 포함 가능)을 출력으로 안전하게 반환 할 수 없음을 의미합니까? 왜냐하면 호출자에서'eval'을 사용하지 않는다면, 스페이스와 구분자 사이의 구별을 잃어 버릴 것이고 나중에이 파일리스트를 반복 할 수 없기 때문입니다. –

+0

@LucasCimon : 함수는 null 문자로 구분 된 목록을 반환 할 수 있지만 ('find -print0'처럼)'$()'구문과 함께 사용할 수 없습니다 -'xargs - 0 '또는'while IFS = read -rd ''argument' 루프를 사용합니다. 이것이 "안전한"이유는'$()'와 함께 사용할 수없는 동일한 이유입니다. C 문자열은 널을 포함 할 수 없기 때문에 인수도'$()'도 처리 할 수 ​​없습니다. –

2

당신은 당신이 반환 된 값에 단어 분리를 해결할 수 있습니다 eval 사용하고자하는 경우 : 당신의 모두에

$ argv_count $'foo\t * bar' 
argv_count('foo * bar'):1 
$ eval argv_count "$(eval identity "$(identity $'foo\t * bar')")" 
argv_count('foo * bar'):1 
+0

이것이 작동하지 않는 몇 가지 이상한 경우가 있습니다. 예를 들어'eval argv_count $ (identity $ 'foo \ t * bar')'를 사용해보십시오. 나는''$ (identity ....) '와 같이 큰 따옴표를 붙이면이 경우를 고쳐 줄 것이라고 생각합니다. –

+0

@GordonDavisson 매력적인 예! 나는 왜 eval argv_count $ (eval identity $ (identity $ 'foo \ t * bar'))'가 잘 동작 하는지를 알지 못하지만,'\ t'를 추가하면 더 간단해진다. 'eval argv_count $ (identity $'foo \ t * bar ')'. 수정으로 큰 따옴표에 관해서는, 그것은 내가 믿는 보금 자리를 깨뜨린다. –

+0

@GordonDavisson 나는 정답으로 btw로 투표했습니다. 나는 단지 내 대답을 지적 호기심이라고 덧붙였다. –