"env" 명령을 통해 줄바꿈으로 값을 설정하는 방법은 무엇입니까?

"env" 명령을 통해 줄바꿈으로 값을 설정하는 방법은 무엇입니까?

내 말은 env다음 형식의 GNU 또는 BSD 명령을 사용한다는 것입니다.env

env [name=value ...] [utility [args ...]]

특수 문자를 부분적으로 이스케이프 처리 할 수 있는 방법은 없는 것 같지만 해당 부분을 구문 분석하는 value방법을 잘 모르겠습니다 .envvalue

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=environvar=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_STRINGenv

이제 이 명령을 실행하기 위해 언어로 코드를 작성할 때 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프로세스가 시작되기 전에 확장되었기 때문에 실제 개행 문자만 표시됩니다).

관련 정보