쉘 스크립트가 주어지면test.sh
for var in "$@"
do
echo "$var"
done
그리고 전화해sh test.sh $(echo '"hello " "hi and bye"')
나는 출력을 기대했다
hello
hi and bye
하지만 다음을 얻으세요:
"hello
"
"hi
and
bye"
내가 다음으로 변경하면sh test.sh $(echo "hello " "hi and bye")
그러면 나는 얻는다
hello
hi
and
bye
이러한 동작 중 어느 것도 바람직하지 않습니다. 원하는 동작을 얻으려면 어떻게 해야 합니까?
내가 이해하고 싶은 것은 왜 동일하지 않습니까 sh test.sh $(echo "hello " "hi and bye")
?sh test.sh "hello " "hi and bye"
답변1
명령 대체는 문자열을 생성합니다.
의 경우
$(echo '"hello " "hi and bye"')
문자열은 "hello " "hi and bye"
.
그런 다음 문자열이 토큰화됩니다(파일 이름 글로빙도 마찬가지이지만 이 예에는 영향을 미치지 않습니다). 토큰화는 문자 중 하나와 동일한 모든 문자 $IFS
(기본적으로 공백, 탭 및 줄 바꿈)에서 발생합니다.
기본값은 IFS
, "hello
, "
, "hi
및 단어 and
를 생성합니다 bye"
.
그런 다음 이를 스크립트에 별도의 매개변수로 제공하십시오.
두 번째 명령에서 명령 대체는 다음과 같습니다.
$(echo "hello " "hi and bye")
그러면 문자열이 생성되고 토큰화는 , , 및 hello hi and bye
4개의 단어를 생성합니다 .hello
hi
and
bye
마지막 예에서는둘매개변수를 사용 hello
하고 hi and bye
스크립트와 함께 직접 사용됩니다. 이것들에 익숙해단어 분할은 인용되기 때문에 발생합니다.
답변2
긴 이야기 짧게: 의 결과는 echo
결과 분할의 희생자 $()
이며 sh test.sh "hello " "hi and bye"
다른 규칙을 사용합니다.
set -x
디버깅을 추가할 때 실제로 어떤 일이 발생하는지 살펴보겠습니다.
> set -x
> ./main.sh $(echo '"hello " "hi and bye"')
++ echo '"hello " "hi and bye"'
+ ./main.sh '"hello' '"' '"hi' and 'bye"'
"hello
"
"hi
and
bye"
echo
"hello " "hi and bye"
이는 명령 자체의 작은따옴표로 인해 단일 인수(예, 모든 공백과 작은따옴표 포함)로 수신됩니다. 그러나 명령 대체는 이를 "hello " "hi and bye"
.dereference 로 바꿉니다 .배쉬 매뉴얼:
큰따옴표 안에 대체가 발생하면 단어 분리 및 경로 이름 확장이 수행되지 않습니다.결과에 대하여.
그러나 귀하의 경우 따옴표 없이 명령을 대체하면 $IFS
공백 문자(단어 분할을 위한 변수에 설정된 3개 문자 중 하나)를 기반으로 단어 분할이 허용됩니다. 따라서 결과 문자열을 모든 공백에서 끊으면 무엇을 얻게 될까요?
"hello
, 공백, 그 뒤에 다음 토큰이 있습니다."
- 양쪽에 공백으로 구분된 문자 자체입니다."hi
, 다시 왼쪽과 오른쪽에 공백이 있습니다.and
bye"
전체적으로 공백으로 인해 손상된 5개의 토큰을 얻게 됩니다. 이 경우 분사는 정확히 명령 대체의 결과라는 점을 인식하는 것이 중요합니다. 그런 다음 이들 모두는 구문 분석된 개별 토큰으로 처리됩니다. set -x
출력에서 볼 수 있듯이 쉘 스크립트는 이러한 태그를 사용하여 호출됩니다 .
성능이 다른 이유는 sh test.sh "hello " "hi and bye"
적용되는 규칙이 다르기 때문입니다. 입력한 명령줄은 입력과 동시에 구문 분석되며 인용된 문자열은 단일 단위로 처리됩니다 hello
.hi and bye
답변3
공백이 아닌 다른 것으로 변경할 수 있습니다 IFS
( 의 공백을 보호하기 위해 hi and bye
). 이를 사용하여 두 문자열을 구분합니다.
$ IFS=:
$ sh test.sh $(echo "hello ":"hi and bye")
hello
hi and bye
(어차피 이 예제와 관련된) 작업 순서는 다음과 같습니다.
- 바꾸다
- 분사
- 견적 삭제
대체 결과로 생성된 따옴표는 토큰화 또는 따옴표 제거 측면에서 특별하지 않으므로 (1) 출력의 따옴표는 다른 문자와 마찬가지로 (2)와 (3)을 통과합니다. 그래서:
- 에서
echo "hello " "hi and bye"
쉘은 이러한 따옴표를 제거하여echo
sumhello
과hi and bye
출력을 얻고hello hi and bye
문자열을 공백으로 연결합니다. - 에서
echo '"hello " "hi and bye"'
쉘은 외부 것을 제거하고'
echo는 이를 가져"hello " "hi and bye"
와서 출력합니다. 명령 대체 에서는 로
sh test.sh $(echo '"hello " "hi and bye"')
대체되지만"hello " "hi and bye"
이것들따옴표는 대체의 결과이므로 단어 분리나 따옴표 제거가 필요하지 않습니다.따라서 쉘은 이를
"hello
,"
,"hi
,and
로 분할하여bye"
출력합니다.- 에서는
sh test.sh $(echo "hello " "hi and bye")
명령 대체가 로 대체되며 이는 , 및hello hi and bye
로 분할 됩니다 .hello
hi
bye
답변4
어때요?
sh test.sh "hello " "hi and bye"
?