heredocs를 명령줄 유틸리티에 파일로 전달하는 방법에 대한 이론이 궁금합니다.
최근에 나는 파일을 heredoc로 전달할 수 있다는 것을 발견했습니다.
예를 들어:
awk '{ split($0, arr, " "); print arr[2] }' <<EOF
foo bar baz
EOF
bar
이는 다음과 같은 이유로 나에게 유리합니다.
- Heredocs는 여러 줄 입력의 가독성을 향상시킵니다.
- 명령줄에서 파일 내용을 전달하기 위해 모든 유틸리티 플래그를 기억할 필요는 없습니다.
- 주어진 파일에서 작은따옴표와 큰따옴표를 사용할 수 있습니다.
- 쉘 확장을 제어할 수 있습니다.
예를 들어:
ruby <<EOF
puts "'hello $HOME'"
EOF
'hello /Users/mbigras'
ruby <<'EOF'
puts "'hello $HOME'"
EOF
'hello $HOME'
무슨 일이 일어났는지 모르겠어요. 쉘은 heredoc를 heredoc 값과 내용이 동일한 파일로 간주하는 것으로 보입니다. 저는 이 기술을 cat과 함께 사용해 보았지만 여전히 무슨 일이 일어나고 있는지 잘 모르겠습니다.
cat <<EOL
hello world
EOL
hello world
나는 cat
인쇄 파일의 내용을 알고 있으므로 아마도 이 heredoc은 일종의 임시 파일일 것입니다.
"명령줄 프로그램에 구분 기호를 전달"할 때 정확히 무슨 일이 일어나고 있는지 혼란스럽습니다.
다음은 사용 예입니다.가능한 스크립트. 플레이북을 heredoc로 유틸리티에 전달했지만 다음을 사용하여 실패했습니다 echo $?
.
ansible-playbook -i localhost, -c local <<EOF &>/dev/null
---
- hosts: all
gather_facts: false
tasks:
- name: Print something
debug:
msg: hello world
EOF
echo $?
5
그러나 동일한 heredoc를 유틸리티에 전달했지만 /dev/stdin
성공하기 전에
ansible-playbook -i localhost, -c local /dev/stdin <<EOF &>/dev/null
---
- hosts: all
gather_facts: false
tasks:
- name: Print something
debug:
msg: hello world
EOF
echo $?
0
- "구분 기호를 파일로 전달"하면 정확히 무슨 일이 발생합니까?
- 첫 번째 버전은
ansible-playbook
실패했지만 두 번째 버전은 성공하는 이유는 무엇입니까? /dev/stdin
heredoc을 통과하는 것이 무슨 의미가 있나요?- 왜 다른 유틸리티가 이전에 heredoc을 좋아
ruby
하거나awk
필요 합니까?/dev/stdin
답변1
"구분된 문서를 파일로 전달"하면 정확히 무슨 일이 발생합니까?
당신은 그렇지 않습니다.여기 문서는 표준 입력을 제공합니다.파이프처럼. 당신의 모범
awk '{ ... }' <<EOF
foo bar baz
EOF
정확히 같다
echo foo bar baz | awk '{ ... }'
awk
, cat
, 및 ruby
표준 입력에서 읽은 모든 것(명령줄에 읽을 수 있는 파일 이름이 제공되지 않은 경우). 이는 구현 선택입니다.
anisble-playbook이 포함된 첫 번째 버전은 실패하지만 두 번째 버전은 성공하는 이유는 무엇입니까?
ansible-playbook
기본적으로 표준 입력에서 읽지 않지만 파일 경로가 필요합니다. 디자인 선택입니다.
/dev/stdin
/dev/fd/0
현재 프로세스에 대해 이야기하는 방법인 심볼릭 링크일 가능성이 높습니다.파일 설명자#0(표준 입력). 이는 커널(또는 시스템 라이브러리)에 의해 노출되는 것입니다. 이 ansible-playbook
명령은 /dev/stdin
일반 파일 시스템 파일처럼 열리고 결국 자체 표준 입력을 읽습니다. 그렇지 않으면 무시됩니다.
아마도 FD 1 과 2 에 대한 /dev/stdout
링크가 있을 것입니다 /dev/stderr
. 이는 출력을 어디에 넣을지 알려주고 싶을 때에도 사용할 수 있습니다.
구분 기호 앞에 /dev/stdin을 전달하는 이유는 무엇입니까?
이는 명령의 매개변수입니다 ansible-playbook
.
Ruby 또는 awk와 같은 다른 유틸리티에서 heredoc 전에 /dev/stdin을 요구하지 않는 이유는 무엇입니까?
기본적으로 파이프라인에서 사용하도록 설계되었으므로 표준 입력을 디자인 선택으로 읽습니다. 같은 이유로 표준 출력에 기록합니다.
답변2
Here-docs에서 정확히 일어나는 일은 쉘이 여기에서 구현하는 방식에 따라 다릅니다 예:dash
(. -doc: 내부적으로 파이프를 사용할 수 있습니다bash
lseek()
관련 답변.
두 ansible-playbook 명령의 경우 명령이 어떻게 구현되는지에 따라 달라집니다(따라서 소스 코드를 읽지 않으면 실제로 알 수 없습니다). 일부 명령은 파일이 제공되고 지원되지 않는지 확인합니다 stdin
. awk
및 -와 같은 다른 명령은 명령줄에서 파일을 ruby
예상하거나 지정하도록 설계되었습니다 .stdin
그러나 시도할 수 있는 것은 Linux를 사용하는 경우 이를 실행하여 strace ansible-playbook ...<other args>
무엇을 열려고 하는지, 어떤 시스템 호출이 발생하는지 등을 확인하는 것입니다. 예를 들어, tail 명령을 사용하면 실제로 파일로 strace -e open tail /dev/stdin <<< "Jello World"
열려고 시도 하지만 그렇지 않은 것을 볼 수 있습니다 ./dev/stdin
trace -e open tail
답변3
here-document는 에서와 같이 명령의 표준 입력으로 리디렉션됩니다 . 이는 리디렉션 파일의 내용을 <
사용할 수 있는 모든 곳에서 here-document의 내용을 리디렉션할 수 있음을 의미합니다 . <
POSIX 표준여기에 있는 문서와 여기에 나열된 기타 리디렉션 연산자.
Ansible 예제에서는 ansible-playbook
파일 이름이 필요하기 때문에 기본적으로 표준 입력 스트림에서 읽지 않습니다. 파일 이름으로 지정한 다음 이 문서를 표준 입력으로 제공하여 /dev/stdin
유틸리티에서 이 제한을 우회할 수 있습니다 . "file /dev/stdin
"은 항상 현재 프로세스의 표준 입력 데이터 스트림을 포함합니다.
ruby
다른 awk
많은 유틸리티는 표준 입력에서 읽습니다.~하지 않는 한파일 이름은 명령줄에 제공됩니다.
그래서 당신은기술적으로"쉘이 heredoc을 heredoc 값과 동일한 내용을 가진 파일로 생각하는 것 같습니다"라고 말하면 이는 잘못된 것입니다. 파일 이름이 있고 검색 가능하다는 측면에서 파일처럼 작동하지 않고 표준 입력의 데이터 스트림으로 작동합니다. 적어도 유틸리티 관점에서는요.
차이점은 다음과 같습니다.
cat file
그리고
cat <file
첫 번째 경우에는 cat
파일이 열리지 file
만 두 번째 경우(여기 문서에서도 마찬가지입니다)에는 파일 이름이 인수로 제공되지 않으므로 cat
표준 cat
입력 스트림만 읽혀집니다(그리고껍데기파일을 열거나 유틸리티의 표준 입력에 이 문서를 제공하십시오. 유틸리티는 제공된 데이터가 파일, 파이프, 여기 문서 또는 기타 데이터 소스에서 나온 것인지 알 필요가 없습니다.
쉘이 이를 구현하는 방법은 여기서 다소 중요하지 않지만 FIFO를 사용하거나 실제로 임시 파일을 사용하는 것일 수 있습니다.