bash에서 명령 전에 변수를 설정하는 이유는 무엇입니까?


68

방금 구분 된 텍스트 파일구문 분석하는 것과 같은 몇 가지 대답이 발생했습니다 ... 구문 을 사용합니다 :

while IFS=, read xx yy zz;do
    echo $xx $yy $zz
done < input_file

여기서 IFS변수는 read명령 전에 설정 됩니다.

나는 bash 참조를 읽었 지만 이것이 왜 합법적인지 알 수 없다.

나는 시도했다

$ x="once upon" y="a time" echo $x $y

bash 명령 프롬프트에서 아무 에코도 얻지 못했습니다. 누군가 IFS 변수를 그런 식으로 설정할 수있는 참조에서 구문이 정의 된 위치를 알려 줄 수 있습니까? 특별한 경우입니까 아니면 다른 변수와 비슷한 것을 할 수 있습니까?


답변:


69

Shell Grammar, Simple Commands (강조 추가)에 있습니다.

간단한 명령은 일련의 선택적 변수 할당 뒤에 공백으로 분리 된 단어와 방향 전환 이 있으며 제어 연산자가 종료합니다. 첫 번째 단어 는 실행할 명령을 지정하고 인수 0으로 전달됩니다. 나머지 단어는 호출 된 명령에 인수로 전달됩니다.

따라서 원하는 변수를 전달할 수 있습니다. 귀하의 echo변수가없는 쉘에서 설정 한 명령에 전달되기 때문에 예를 작동하지 않습니다. 쉘이 확장 $x되어 명령을 호출 $y 하기 전에 . 예를 들면 다음과 같습니다.

$ x="once upon" y="a time" bash -c 'echo $x $y'
once upon a time

감사! 나는 묻기 전에 많은 인터넷 검색을 해 왔으며 참조에서 행운이없는 곳을 찾으려고 노력했습니다. bash 스크립트 작성을 더 잘하려고 노력하고 있으며 귀하의 답변이 도움이됩니다.
Mike Lippert

1
흠 나는 더 나은 참조를 찾아야한다고 생각한다. (위의 링크 참조) 쉘 문법 섹션이 없다고 말하지는 않는다.
Mike Lippert

1
@MikeLippert 해당 참조의 3.7.4를 참조하십시오 ( "단순한 명령 또는 기능의 환경은 매개 변수 지정 접두어를 사용하여 일시적으로 기능을 보강 할 수 있습니다"). 참조는 이전 버전의 bash에서 가져온 것 같습니다. 방금 man bash시스템을 실행 했습니다 ...
derobert

29

정의 된 변수는 분기 프로세스에서 환경 변수처럼됩니다.

당신이 실행하는 경우

A="b" echo $A

bash는 먼저 확장 $A되어 ""실행됩니다.

A="b" echo

올바른 방법은 다음과 같습니다.

x="once upon" y="a time" bash -c 'echo $x $y'

의 작은 따옴표를 주목하십시오 bash -c. 그렇지 않으면 위와 같은 문제가 있습니다.

bash 내장 '읽기'명령은 환경 변수에서 IFS를 찾고 찾기 때문에 루프 예제가 적합 ,합니다. 따라서,

for i in `TEST=test bash -c 'echo $TEST'`
do
  echo "TEST is $TEST and I is $i"
done

인쇄합니다 TEST is and I is test

마지막으로 구문은 for 루프에서 문자열이 예상됩니다. 따라서 나는 그것을 명령으로 만들기 위해 백틱을 사용해야했다. 그러나 while 루프는와 같은 명령 구문을 필요로 IFS=, read xx yy zz합니다.


1
고마워, 나는 당신의 대답보다 조금 더 배웠습니다. 귀하의 답변에 투표를했지만 아직 허용되지 않았으며 첫 번째 답변에 허용 된 답변을 표시했습니다.
Mike Lippert

1
고마워, 그게 내가 바랐던 일이야 그리고 투표는 당신의 감사를 듣는 것보다 덜 의미가 있습니다!
Mike Fairhurst

첫 번째 코드 줄에서 주석을 명확히하려면 : 예, 설정되지 않은 A변수 bash $A를 사용하면 빈 문자열로 확장 되지만 혼동을 피하기 위해 ""코드가와 같지 않기 때문에 사용하지 않을 것 A="b" echo ""입니다. 에 대한 논쟁은 없을 것 echo입니다.
pabouk

8

man bash

환경

[...] 간단한 명령 또는 기능의 환경은 PARAMETERS에서 위에서 설명한 것처럼 매개 변수 할당으로 접두어를 사용하여 임시로 보강 할 수 있습니다. 이러한 할당 문은 해당 명령으로 보이는 환경에만 영향을줍니다.

변수 할당이 수행되기 전에 변수가 확장됩니다. 명백한 이유로 var=x다른 방식으로도 작동하지만 그렇지 var=$othervar는 않습니다. 즉, $x사용하기 전에 필요합니다. 그러나 이것이 주요 문제는 아닙니다. 주요 문제점은 명령 행을 쉘 환경에서만 수정할 수 있지만 지정은 쉘 환경의 일부가되지 않는다는 것입니다.

기능을 혼합 한 경우 : 명령 행을 바꾸고 싶지만 변수 정의를 명령 환경에 넣습니다. 명령 행은 쉘에서 교체해야합니다. 호출 된 명령에서 환경을 명시 적으로 사용해야합니다. 이것이 수행되는지 여부와 방법은 명령에 따라 다릅니다.

이 사용법의 장점은 쉘 환경에 영향을주지 않고 서브 프로세스에 대한 환경을 설정할 수 있다는 것입니다.

x="once upon" y="a time" bash -c 'echo $x $y'

이 경우 두 기능이 결합되기 때문에 예상대로 작동합니다. 명령 행 교체는 호출 쉘이 아니라 하위 프로세스 쉘에 의해 수행됩니다.


1
이 예제는 내장 x="once upon" y="a time" eval 'echo $x $y'프로세스이므로 하위 프로세스가 포함되지 않은 경우 에도 작동하기 때문에 그보다 조금 미묘 eval합니다. 맨 페이지의 관련 견적은 The environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments입니다. 질문의 예를 고려할 때이 방법 read은 내장되어 있기 때문에 일시적으로 변경된 상태로 작동 하므로이 방법이어야합니다 IFS.
David Ongaro

4

사용자가 제공하는 명령 때문에 다른 $x$y확장됩니다 전에echo 명령이 실행, 그래서 자신의 값을 현재의 쉘이 아닌 값을 사용하는 echo것이 본다면 환경에서 볼 것입니다.


명령이 실행 된 후 명령 행에서 무엇을 확장 할 수 있습니까?
Hauke ​​Laging

인수 가 확장 되는 환경이 아니라 실행 되는 환경에 대한 사전 명령 지정 x및 실행 . 의 경우 명령에 의해 전체 문자열이 분리되지 않고 읽 힙니다 . 그런 다음 해당 문자열은 값에 따라 분할 되고 해당 조각 은 , 및에 할당됩니다 . yechoechoIFS=, read xx yy zzreadIFSxxyyzz
chepner

"명령이 실행되기 전에 확장되었다"라는 말은 명령이 시작된 후에는 더 이상 확장되지 않기 때문에 의미가 없다는 것을 지적하고 싶었습니다. 또한 : 당신은 내 대답을 한 번 보지 않았거나 그럼에도 불구하고 무슨 일이 일어나고 있는지에 대한 설명이 필요하다고 믿습니까?
Hauke ​​Laging

1
나는 당신에게 설명이 필요하다고 주장하지 않았으며 명령이 실행 된 후에 무엇이든 확장 할 수 있다고 주장하지 않았습니다. 그러나 bash주어진 명령 행 을 먼저 구문 분석하고 다가오는 명령의 환경에 적용 할 두 가지 변수 지정이 있음을 인식하고 실행할 명령을 식별하고 ( echo) 인수에서 찾은 매개 변수를 확장 한 다음 명령 실행하는 것이 사실입니다. echo확장 된 주장으로.
chepner

의 경우 echo는 자신의 환경을 수있는 서브 쉘에서 실행되지 않습니다 따라서 내장 명령이고 이후는, 변수 "를 참조하십시오"수 있는지 확실하지 않았다. 그러나 나는 eval또한 내장 된 것을 사용해 보았으며 실제로 그것에 대해 알고 있습니다. 예를 들어 pid가 동일하고 평가 기간 동안 환경이 변경되지 않은 경우 에만 설정 a=xyz eval 'echo $BASHPID $a; grep -z ^a /proc/$BASHPID/{,task/*}/environ'; echo $BASHPID $a되는 것을 보여줍니다 ! (액세스 하려면 Linux에서 이것을 실행해야합니다.) bash는 여기서 추가 마술을 수행하는 것 같습니다. aeval/proc
David Ongaro

2

" 합법적 인지 "에 대한 더 큰 그림을 보려고합니다.

답 : 프로그램을 호출하거나 호출 할 수 있도록하려면 특정 변수가있는 변수 만 사용하십시오.

예를 들어, 'db_connection'이라는 데이터베이스 연결에 대한 매개 변수가 있으며 일반적으로 테스트 데이터베이스 연결의 이름으로 'test'를 전달합니다. 실제로 명시 적으로 전달할 필요가없는 기본값으로 설정할 수도 있습니다. 그러나 때로는 ci 데이터베이스로 작업하려고합니다. 따라서 매개 변수를 'ci'로 전달하면 호출되는 프로그램은 해당 데이터베이스 매개 변수를 모든 데이터베이스 호출에 사용할 db의 이름으로 사용합니다. 다음 실행의 경우 접근 방식을 반복하지 않고 프로그램을 호출하면 변수가 이전 기본값으로 돌아갑니다.


0

을 사용할 수도 있습니다 ;. 명령 구분 기호이므로 이전에 평가됩니다.

x="once upon" y="a time"; echo $x $y

1
이것은 두 개의 쉘 변수를 작성하며 주어진 유틸리티에서 환경 변수를 작성하지 않습니다. 이것은 매우 다른 것입니다. 현재 쉘에 새로운 변수가 있다는 부작용도 있습니다.
Kusalananda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.