내 말은 env
다음 형식의 GNU 또는 BSD 명령을 사용한다는 것입니다.env
env [name=value ...] [utility [args ...]]
특수 문자를 부분적으로 이스케이프 처리 할 수 있는 방법은 없는 것 같지만 해당 부분을 구문 분석하는 value
방법을 잘 모르겠습니다 .env
value
env
쉘의 기능을 통해 이 작업을 수행할 수 있는 방법이 여러 가지 있다는 것을 알고 있지만 쉘의 도움 없이 리터럴 문자열을 전달하고 싶습니다(execute by 와 유사 exec
). 즉, 명령에서 지원하는 개행 문자가 포함된 일부 env
리터럴 문자열 형식을 찾아야 합니다. 예를 들어:
env FOO=LITERAL_STRING ruby -e 'puts ENV["FOO"]'
여기에는 LITERAL_STRING
개행 문자가 포함된 리터럴 문자열이 포함되어야 하며 env
형식을 이해해야 합니다.
위 명령을 사용하면 예상되는 출력은 다음과 같아야 합니다.
hello
world
가능한지 알고 싶습니다. 귀하의 도움에 감사드립니다.
환경
env
BSD를 사용하고 있어서
env
버전을 인쇄할 수 없습니다. 이것이man
도움이 될지 확실하지 않습니다.$ man env | tail -n1 BSD April 17, 2008 BSD
운영 체제
$ sw_vers ProductName: macOS ProductVersion: 11.6 BuildVersion: 20G165
답변1
귀하의 이해가 잘못되었습니다. "hello\nworld"
변수에 무언가를 저장하면 \n
문자 그대로 해석됩니다. printf
또는 플래그 echo
와 같은 도구를 호출하는 경우에만 -e
콘솔에 인쇄할 때 이러한 백슬래시 시퀀스를 확장합니다.
귀하의 경우 변수를 환경에 전달하고 개행을 확장하려는 경우 다음을 사용하는 것이 좋습니다.ANSI C 스타일 $'...'
참조 연산자ksh93 버전은 이제 bash 및 zsh를 포함한 여러 다른 셸에서 지원됩니다.
env FOO=$'hello\nworld' ruby -e 'puts ENV["FOO"]'
또는 이식성이 문제인 경우 간단한 해결책은 원하는 위치에 개행 문자를 배치하는 것입니다.
f="hello
world"
env FOO="$f" ruby -e 'puts ENV["FOO"]'
답변2
암소 비슷한 일종의 영양그리고FreeBSD env
-S
인수를 공백으로 분할한 다음 결과 문자열에서 다음을 포함하되 이에 국한되지 않는 많은 수의 이스케이프 문자를 해석하는 ("분할") 옵션[1]이 있습니다 \n
.
$ env -S 'foo=bar\nquux printenv foo'
bar
quux
$ env -S 'foo=bar\nquux' printenv foo
bar
quux
[1] 기본 용도는 shebang 라인용이지만 명령줄이 필요한 다른 곳에서도 사용할 수 있지만 대부분의 vte 기반 터미널 옵션 #! ...
처럼 이를 해석하기 위해 쉘 대신 임시 파서를 사용합니다 .-e
답변3
이 env
명령은 실행될 때 시스템 호출에서 여러 매개변수를 가져옵니다(다른 명령과 마찬가지로) execve()
. 이를 실행하는 프로세스는 다음을 수행합니다.
execve("/path/to/env", ["env", "-options", "var=value", "cmd", "arg"], environ);
순차적으로 실행 됩니다 env
(보통 동일한 프로세스 내에서).
execve("/path/to/cmd", ["cmd", "arg"], modified_environ);
어디에 modified_environ
가 있지만 environ
가 추가되거나, in 으로 시작하는 문자열이 var=value
이미 하나 이상 있는 경우 그 중 첫 번째 문자열이 (적어도) 로 대체됩니다 .var=
environ
var=value
이러한 매개변수는 NUL로 끝나는 바이트 배열이므로 포함할 수 없는 유일한 바이트는 NUL 바이트입니다. 이름과 값에 NUL 바이트를 포함할 수 없는 환경 변수에도 동일하게 적용됩니다.
env
시작 시 해당 매개변수는 처음부터 끝까지 처리됩니다.
으로 시작하는 것은 -
옵션으로 간주됩니다.
-
혼자서도 고대 형태로 -i
무시 됩니다 environ
.
--
적어도 하나를 포함하는(또는 옵션의 끝을 표시하는 데 사용할 수 있는) 다음 옵션은 =
환경 변수 문자열(위에 배치됨)로 처리됩니다 modified_environ
. 문자가 포함되지 않은 옵션이 아닌 첫 번째 인수는 =
명령 이름으로 처리됩니다(첫 번째 인수로 명령에 전달되며 조회에서 실행 파일에 대한 경로로도 사용됩니다 $PATH
).
-
이 이후의 모든 인수는 문자로 시작하거나 문자를 포함 하더라도 명령에 대한 인수로 전달됩니다 =
.
따라서 및 문자만 env
그 자체로 특별합니다 . 옵션 처리 중에만, 명령 이름을 찾기 전에만 가능합니다.-
=
-
=
-
로 시작하는 환경 변수 이름 이나 로 시작하는 명령 이름을 전달하려면 -
다음을 사용할 수 있습니다 --
.
execve("/usr/bin/env", ["env", "--", "-var-=value", "cmd"], environ);
execve("/usr/bin/env", ["env", "--", "-cmd-"], environ);
여러 env
구현 의 경우 -
다음 것만 으로는 --
여전히 명령 이름으로 간주되지 않습니다. 따라서 이름이 지정된 명령을 호출하려면 -
미리 하나 이상의 환경 변수를 전달해야 합니다.
execve("/usr/bin/env", ["env", "--", "dummy=", "-", "args"], environ);
(또는 대신 /path/to/-
또는 명령의 경로 조회를 무시하고 사용하십시오 )../-
-
$PATH
-
env
=
그러나 이름에 문자가 포함되어 =
전달 될 수 없는 명령은 실행할 수 없습니다 modified_environ
. =
이 경우 이 역할을 피할 수 있는 방법이 없습니다.
그러나 귀하의 경우 NUL 바이트를 제외하고 env
FOO=LITERAL_STRING
문자 자체는 문제가 되지 않습니다 .LITERAL_STRING
env
이제 이 명령을 실행하기 위해 언어로 코드를 작성할 때 env
해당 언어에는 문자 그대로 입력할 수 없는 문자가 있을 수 있습니다.
예를 들어 에서는 perl
다음을 수행할 수 있습니다.
exec "env", "--", "-text-=hello\nworld\n", "printenv", "--", "-text-";
개행 문자를 큰따옴표 안에 넣어 표현 \n
하지만 다음과 같이 할 수도 있습니다:
exec qw(env --), q(-text-=hello
world
), qw(printenv -- -text-);
개행 문자가 포함된 문자열을 전달합니다.
Bourne과 유사한 쉘 언어의 구문에서 개행 문자는 작은 따옴표나 큰 따옴표(예: q(...)
또는 qq(...)
참조 연산자 perl
) 안에 있을 때 특별하지 않으므로 다음과 같이 할 수 있습니다.
exec env -- "-text-=hello
world
" printenv -- -text
"..."
참조 연산자가 사용되지 않는 C 쉘이나 rc 쉘에서는 상황이 다릅니다 .
귀하의 env FOO=LITERAL_STRING ruby -e 'puts ENV["FOO"]'
코드는 쉘 언어의 코드처럼 보입니다. 거의 모든 쉘이 공백을 단어 구분 기호 및 '...'
인용 연산자 로 이해하기 때문에 이 구문은 대부분의 쉘에 유효합니다 .
exec
처음에 이를 생략 하면 쉘은 하위 프로세스에서 명령을 실행한 다음 해당 프로세스가 종료되거나 중단될 때까지 기다립니다.
이것이 개행 문자를 문자 그대로(아마도 쉘이 아님) 입력하거나 어떤 형태의 인코딩( , , ...) 을 허용하지 않지만 대부분의 쉘과 같은 인용 연산자를 분명히 지원하는 env FOO=LITERAL_STRING ruby -e 'puts ENV["FOO"]'
언어라면 BSD가 이미 트릭을 수행하는 것을 제외하고\n
%0a
'...'
env -S
@UncleBilly가 제안함perl
, 명령을 실행할 수 있고 , , ruby
, python
, ksh93
, ... 와 같은 일부 인코딩에서 개행 문자를 지정할 수 있는 언어 또는 인터프리터를 호출할 수 있습니다 zsh
.bash
이미 가지고 있으므로 ruby
:
ruby -e 'exec "env", "FOO=a\n\n\nb", *ARGV' -- ruby -e 'puts ENV["FOO"]'
그러나 모든 계보 프로그래밍 언어는 ruby
자체적으로 환경 변수를 설정할 수 있으므로 다음을 수행할 필요가 없습니다 env
.
ruby -e 'ENV["FOO"]="a\n\n\nb"; exec *ARGV' -- ruby -e 'puts ENV["FOO"]'
답변4
값에 리터럴 줄 바꿈을 사용하십시오.
$ env FOO="hello
world" ruby -e 'puts ENV["FOO"]'
산출:
hello
world
문자열을 실제 개행 문자로 변환하려면 \n
다음과 같은 유틸리티를 사용하십시오 printf
.
$ env FOO="$(printf "%b" 'hello\nworld')" ruby -e 'puts ENV["FOO"]'
hello
world
env
이와 관련하여 특별한 것은 없습니다(사실 env
프로세스가 시작되기 전에 확장되었기 때문에 실제 개행 문자만 표시됩니다).