파이프의 두 번째 명령에 대해 Bash의 명령 전에 환경 변수 설정이 작동하지 않습니다


351

주어진 쉘에서 일반적으로 변수 또는 변수를 설정하고 명령을 실행합니다. 최근에 변수 정의를 명령 앞에 추가하는 개념에 대해 배웠습니다.

FOO=bar somecommand someargs

이것은 작동합니다 ... LC_ * 변수를 변경하거나 ( 예 : '[az]'char 범위와 같은 인수에는 영향을 미치지 않는 것처럼 보이는) LC_ * 변수를 변경 하거나 출력을 다른 명령으로 파이핑 할 때 작동 하지 않습니다 .

FOO=bar somecommand someargs | somecommand2  # somecommand2 is unaware of FOO

"FOO = bar"를 사용하여 somecommand2를 앞에 추가 할 수도 있는데, 이는 작동하지만 원치 않는 중복을 추가하며 변수에 따라 해석되는 인수 (예 : '[az]')에는 도움이되지 않습니다.

그렇다면 한 줄 로이 작업을 수행하는 좋은 방법은 무엇입니까?

나는 순서대로 뭔가를 생각하고있다.

FOO=bar (somecommand someargs | somecommand2)  # Doesn't actually work

나는 좋은 답변을 많이 받았습니다! 목표는 이것을 "내보내기"를 사용하지 않고 하나의 라이너로 유지하는 것입니다. Bash 호출을 사용하는 방법은 전체적으로 가장 좋았지 만 "내보내기"가 포함 된 괄호 버전은 조금 더 콤팩트했습니다. 파이프 대신 리디렉션을 사용하는 방법도 흥미 롭습니다.


1
(T=$(date) echo $T)작동합니다
— vp_arth

크로스 플랫폼 (윈도우 포함) 스크립트 또는 npm 기반 프로젝트 (js 또는 기타)와 관련하여 크로스 env 모듈을 살펴볼 수 있습니다 .
— Frank Nocke

5
나는 대답 중 하나가 왜 이런 종류의 작품인지, 즉 호출 전에 변수를 내보내는 것과 같은 이유 를 설명하기를 바랐 습니다.
— Brecht Machiels

4
이유는 여기에 설명되어 있습니다 : stackoverflow.com/questions/13998075/…
— Brecht Machiels

답변:


317
FOO=bar bash -c 'somecommand someargs | somecommand2'

2
이것은 내 기준 ( "내보내기"가 필요없는 한 줄짜리)을 충족합니다. "bash -c" 를 호출 하지 않고 (예 : 괄호를 창의적으로 사용) 이를 수행 할 수있는 방법이 없습니다 .
— MartyMacGyver 2016 년

1
@MartyMacGyver : 생각할 수있는 것은 없습니다. 중괄호와도 작동하지 않습니다.
— 추후 공지가있을 때까지 일시 중지되었습니다.

7
somecommandsudo 로 실행해야하는 경우 -E변수를 전달 하려면 sudo 플래그를 전달해야합니다. 변수가 취약점을 일으킬 수 있기 때문입니다. stackoverflow.com/a/8633575/1695680
— ThorSummoner

11
명령에 이미 두 단계의 인용 부호가 있으면이 방법은 인용 부호 때문에 매우 불만족스러워집니다. 이 상황에서 서브 쉘로 내보내는 것이 훨씬 좋습니다.
— Pushpendre

홀수 : OSX에서 FOO_X=foox bash -c 'echo $FOO_X'예상대로 작동하지만 특정 var 이름으로 실패합니다 : DYLD_X=foox bash -c 'echo $DYLD_X'echos blank. 둘 다 eval대신 사용bash -c
— mwag

209

변수를 내보내고 서브 쉘에서만 내보내는 것은 어떻습니까? :

(export FOO=bar && somecommand someargs | somecommand2)

Keith는 명령을 무조건 실행하려면 다음과 같이하십시오.

(export FOO=bar; somecommand someargs | somecommand2)

15
나는 ;오히려 사용 &&한다; export FOO=bar실패 할 방법 이 없습니다.
— 키이스 톰슨

1
@MartyMacGyver : &&왼쪽 명령을 실행 한 다음 왼쪽 명령이 성공한 경우에만 오른쪽 명령을 실행합니다. ;두 명령을 무조건 실행합니다. Windows 배치 ( cmd.exe)는 ;입니다 &.
— 키이스 톰슨

2
zsh에서는이 버전에 대한 내보내기가 필요하지 않은 것 같습니다 : (FOO=XXX ; echo FOO=$FOO) ; echo FOO=$FOOyields FOO=XXX\nFOO=\n.
— rampion

3
@PopePoopinpants : 그 경우 source(일명 .)을 사용하지 않는 이유는 무엇입니까? 또한 요즘에는 백틱을 더 이상 사용해서는 안되며 이것이 사용 $(command)이 더 안전한 이유 중 하나입니다 .
— 0xC0000022L

3
아주 단순하면서도 우아합니다. 그리고 나는 현재 답변과 같은 하위 셸을 시작하기 때문에 ( bash예를 들어 다른 것일 수도 있지만 dash) 따옴표를 사용해야하는 경우 아무런 문제가 발생하지 않으므로 허용 된 답변보다 귀하의 답변이 더 좋습니다. args 명령 ( someargs) 내에서 .
— Mecki

45

당신은 또한 사용할 수 있습니다 eval:

FOO=bar eval 'somecommand someargs | somecommand2'

이 답변은 eval모든 사람을 기쁘게하는 것 같지 않으므로 무언가를 명확히하겠습니다 . 작은 따옴표와 함께 서면으로 사용될 때 완벽하게 안전합니다. 허용되는 답변과 같은 외부 프로세스를 시작하지 않거나 다른 답변과 같은 추가 하위 쉘에서 명령을 실행하지 않기 때문에 좋습니다.

우리가 몇 가지 정기적 인 견해를 얻었을 때, eval모든 사람들을 기쁘게 할 대안을 제공하는 것이 좋으며 ,이 빠른 eval“속임수”의 모든 이점 (그리고 아마도 더 많은 것)이 있습니다. 그냥 기능을 사용하십시오! 모든 명령으로 함수를 정의하십시오.

mypipe() {
    somecommand someargs | somecommand2
}

다음과 같이 환경 변수로 실행하십시오.

FOO=bar mypipe

7
@Alfe : 당신은 또한 받아 들여진 대답을 downvote 했습니까? 와 같은 "문제"를 나타 내기 때문 eval입니다.
— gniourf_gniourf

10
@Alfe : 불행히도 나는 당신의 비판에 동의하지 않습니다. 이 명령은 완벽하게 안전합니다. 당신 eval은 한 번 읽은 사람 이 악한 것을 이해하지 않고 악한 것처럼 들립니다 eval. 그리고 아마도이 답변을 실제로 이해하지 못할 수도 있습니다 (실제로는 아무런 문제가 없습니다). 같은 수준에서, 당신은 그것이 ls나쁘기 때문에 나쁘다고 말할 것 for file in $(ls)입니까? (그렇습니다, 당신은 받아 들여진 대답을 공감하지 않았으며, 의견도 남기지 않았습니다). SO는 때때로 이상하고 터무니없는 곳입니다.
— gniourf_gniourf

7
내가 말할 때 @Alfe는 당신은 정말 읽기 일단 사람처럼 소리 eval에 대한 악 무엇을 이해하지 않고 악이다 eval, 나는 당신의 문장을 말하는 겁니다이 : 이 답변은 경고와 필요한 설명에 대해 이야기 모든 부족하다 eval. eval나쁘거나 위험하지 않습니다. 더 이상 bash -c.
— gniourf_gniourf

1
표를 제외하고 @Alfe가 제공 한 의견은 수용 된 답변이 어떻게 든 더 안전하다는 것을 암시합니다. 더 도움이 된 것은의 사용법에 대해 안전하지 않다고 생각하는 것을 설명하는 것이었을 것입니다 eval. 대답에서 인수는 변수 확장으로부터 보호하는 작은 따옴표로 묶여 있으므로 대답에 아무런 문제가 없습니다.
— Brett Ryan

하나의 새로운 의견에 관심을 집중시키기 위해 의견을 삭제 eval했습니다. 일반적으로 보안 문제 bash -c이지만 ( 명확하지는 않지만) 그 사용을 제안하는 답변에 위험을 언급해야합니다. 부주의 한 사용자는 답변 ( FOO=bar eval …)을 받아 상황에 적용하여 문제를 일으킬 수 있습니다. 그러나 응답자에게는 내가 무엇을 개선하는 것보다 내가 그의 및 / 또는 다른 답변을 하향 투표했는지 여부를 파악하는 것이 더 중요했습니다. 앞에서 쓴 것처럼 공정성이 주요 관심사가되어서는 안됩니다. 존재하지 나쁘지 다른 주어진 답보다도 선명하게 촬상입니다.
— Alfe

12

사용하십시오 env.

예를 들면 다음과 같습니다 env FOO=BAR command. 다음과 같은 경우 환경 변수가 다시 복원 / 변경되지 않습니다.command 실행이 끝나면 .

쉘 대체가 일어나지 않도록주의하십시오. 즉 $FOO, 동일한 명령 행에서 명시 적으로 참조하려는 경우 쉘 인터프리터가 실행 전에 대체 를 수행하지 않도록이를 벗어나야 할 수도 있습니다 env.

$ export FOO=BAR
$ env FOO=FUBAR bash -c 'echo $FOO'
FUBAR
$ echo $FOO
BAR

-5

쉘 스크립트를 사용하십시오.

#!/bin/bash
# myscript
FOO=bar
somecommand someargs | somecommand2

> ./myscript

13
여전히 필요합니다 export. 그렇지 않으면 $FOO환경 변수가 아닌 쉘 변수가되므로 somecommand또는에 표시되지 않습니다 somecommand2.
— Keith Thompson

그것은 효과가 있지만 한 줄 명령의 목적을 상실합니다 (상대적으로 간단한 경우를 위해 멀티 라이너 및 / 또는 스크립트를 피하는 더 창의적인 방법을 배우려고합니다). 그리고 @Keith가 말한 것은 적어도 내보내기는 스크립트 범위를 유지합니다.
— MartyMacGyver 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.