파이프의 두 번째 명령에 대해 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.