![쉘이 $(의 부분 출력을 처리하는 이유는 무엇입니까?](https://linux55.com/image/132295/%EC%89%98%EC%9D%B4%20%24(%EC%9D%98%20%EB%B6%80%EB%B6%84%20%EC%B6%9C%EB%A0%A5%EC%9D%84%20%EC%B2%98%EB%A6%AC%ED%95%98%EB%8A%94%20%EC%9D%B4%EC%9C%A0%EB%8A%94%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F.png)
읽다가 이 줄을 봤는데IFS에 관한 블로그그건:
for i in $(<test.txt)
그리고 $(<test.txt)
파일 내용을 STDOUT으로 인쇄하는 것을 생각해 보세요. 제가 틀렸을 수도 있지만 호기심 때문에 쉘에서 이 작업을 시도해 보았습니다. 따라서 array
임의의 데이터로 이름이 지정된 임의의 파일이 선택되고
먼저 하나를 수행하면 cat array
다음과 같은 결과가 나왔습니다.
amit@C0deDaedalus:~/test$
amit@C0deDaedalus:~/test$ cat array
1) Ottawa Canada 345644
2) Kabul Afghanistan 667345
3) Paris France 214423
4) Moscow Russia 128793
5) Delhi India 142894
그러면 $(<array)
나에게 다음이 제공됩니다.
amit@C0deDaedalus:~/test$ $(<array)
1) Ottawa Ca: command not found
입력 리디렉션에 사용된다는 것만 알지만 <
쉘이 여기에서 이를 명령으로 해석하는 것이 무엇인지 정확히 알지 못합니다.
쉘에서 이 이상한 출력 뒤에 있는 개념을 설명할 수 있는 사람이 있습니까?
고쳐 쓰다:-
실행하면 set -x
다음이 제공됩니다.
amit@C0deDaedalus:~/test$ $(<array)
+ '1)' Ottawa Canada 345644 '2)' Kabul Afghanistan 667345 '3)' Paris France 214423 '4)' Moscow Russia 128793 '5)' Delhi India 142894
+ '[' -x /usr/lib/command-not-found ']'
+ /usr/lib/command-not-found -- '1)'
1): command not found
+ return 127
amit@C0deDaedalus:~/test$
답변1
이 $(command)
구문은 서브셸 환경에서 실행되며 command
자체적으로 and로 대체됩니다 command
.Bash 매뉴얼에 따르면, $(< file)
단지 더 빠른 것과 같습니다 $(cat file)
(그러나 POSIX 기능은 아닙니다).
따라서 를 실행하면 $(<array)
Bash는 해당 대체를 수행한 다음 첫 번째 필드를 명령 이름으로 사용하고 나머지 필드를 명령에 대한 인수로 사용합니다.
$ $(<array)
1): command not found
명령/기능 이 없으므로 1)
오류 메시지가 인쇄됩니다.
그러나 특정 시나리오에서는 IFS 변수를 수정했기 때문에 다른 오류 메시지가 나타날 수 있습니다.
$ IFS=n; $(<array)
1) Ottawa Ca: command not found
편집 1
내 생각엔 당신의 IFS
코드가 수정되었기 때문에 쉘이 1) Ottawa Ca
대신 실행을 시도하는 것입니다 1)
. 결국 당신은 IFS
관련 기사를 읽고 있는 것입니다. IFS
이상한 값이 나와도 놀라지 않을 것입니다.
이 IFS
변수는 소위분사또는필드 분할. 이는 기본적으로 쉘이 확장된 컨텍스트(또는 예를 들어 다른 명령)에서 데이터를 구문 분석하는 방법을 정의합니다 read
.
3.5.7 분사
쉘은 단어 분할을 위해 큰따옴표 안에 표시되지 않는 인수 확장, 명령 대체 및 산술 확장의 결과를 스캔합니다.
쉘은 각 문자를
$IFS
구분 기호로 처리하고 이러한 문자를 필드 종결자로 사용하여 다른 확장 결과를 단어로 분할합니다. 설정 되지IFS
않거나 해당 값이 기본값인 경우<space><tab><newline>
이전 확장 결과의 시작과 끝 부분에 있는 , 및 의 시퀀스는 무시되고<space>
시작<tab>
이나 끝이 아닌 문자 시퀀스는 단어를 구분하는 데 사용됩니다. 기본값이 아닌 값을 사용하면 공백 문자가 (공백) 값 내에 있는 한 단어의 시작과 끝 부분에 있는 공백 문자 , , 및 시퀀스는 무시됩니다. 공백이 아닌 문자와 인접한 공백 문자는 별도의 필드입니다. 공백 문자 시퀀스도 구분 기호로 간주됩니다. 값이 비어 있으면 단어 분할이 발생하지 않습니다.<newline>
IFS
IFS
space
tab
newline
IFS
IFS
IFS
IFS
IFS
IFS
IFS
명시적 빈 인수(
""
또는''
)는 유지되어 빈 문자열로 명령에 전달됩니다. 값이 없는 매개변수 확장으로 인해 암시적으로 인용되지 않은 null 매개변수는 제거됩니다. 값이 없는 인수를 큰따옴표로 확장하면 빈 인수가 생성되며, 이는 유지되어 빈 문자열로 명령에 전달됩니다. null이 아닌 확장된 단어의 일부로 인용된 null 인수가 발생하면 null 인수가 제거됩니다. 즉, 단어 분할 및 빈 매개변수 제거 후에 해당 단어가 됩니다-d''
.-d
확장이 발생하지 않으면 분할이 수행되지 않습니다.
IFS
다음은 명령 대체 사용의 몇 가지 예 입니다 .
예시 1:
$ IFS=$' \t\n'; var='hello world'; printf '[%s]\n' ${var}
[hello]
[world]
$ IFS=$' \t\n'; var='hello world'; printf '[%s]\n' "${var}"
[hello world]
두 경우 모두 IFS
is <space><tab><newline>
(기본값), var
is hello world
및 명령문이 있습니다 printf
. 그러나 첫 번째 경우에는 단어 분리가 수행되지만 두 번째 경우에는 그렇지 않습니다(큰따옴표가 해당 동작을 억제하기 때문).비참조 확장에서는 토큰화가 발생합니다.
예 2:
$ IFS='x'; var='fooxbar'; printf '[%s]\n' ${var}
[foo]
[bar]
$ IFS='2'; (exit 123); printf '[%s]\n' ${?}
[1]
[3]
공백 문자도 없고 공백 문자도 포함되어 있지 ${var}
않으므로 ${?}
이 경우 단어 분할이 문제가 되지 않을 것이라고 생각할 수도 있습니다. 하지만 이는 남용될 수 있으므로 그렇지 않습니다 IFS
.IFS
거의 모든 가치를 저장할 수 있으며 쉽게 남용될 수 있습니다.
예시 3:
$ $(echo uname)
Linux
$ $(xxd -p -r <<< 64617465202d75)
Sat Apr 28 12:46:49 UTC 2018
$ var='echo foo; echo bar'; eval "$(echo "${var}")"
foo
bar
이는 토큰화와는 아무 관련이 없지만 코드를 삽입하기 위해 몇 가지 더러운 트릭을 사용하는 방법에 주목하세요.
관련 질문: