Here Documents / Inline Input Redirection AND Here String.

Python 에서도 이 문구를 봤고, Bash 에서도 그랬다.
그러나, 정작 이해를 하진 못했었다.
책의 설명도 부족했고, 혼자서, 읽기만해서 이해하기(讀解)엔 어려움이 있었다.

그걸, 오늘 드디어 이 난관을 극복했다. 시작점은 mp3/flac 의 tag 을 CLI 로 처리하려는 의도였었는데, 하나씩 걸려넘어지다보니 여기에까지 이르게 되었다.
이 글을 시작으로, 그 돌뿌리 들을 걷어내는 작업을 기록할 예정이다.


Here Document. 사실, 단어 뜻 그대로다. 이 표현이 ‘일반 표현’으로 많이 쓰이는 듯 하고, Inline Input Redirection(Linux Command Line and Shell Scripting Bible p280)라고도 하나보다.
Here, ‘여기’에, Document, ‘문서’가 있다는 뜻이 된다. (간단한, 내 나름대로의 정의는 이 글 끝에 있다.)

그럼, 여기는 어디고, 문서란 뭘 말하는 걸까?
내가 본 몇몇 책엔 이에 대한 자세한(그야말로 Dummy 를 위한) 설명은 없었다. 이게 뭔지를 아는 사람들에게 그저 살짝 환기(喚起)용으로 써놓은 정도가 대부분이었다.

그럼, ‘바보’인 내게, 내가 설명을 해보도록 하겠다.
이런 가정을 해보자.

  • Shell 프로그램 내에서 cat 을 사용해서 일련의 문자열을 출력해야 한다.
  • cat 의 대상이 되는 문자열들은, 아직 ‘파일’로서 존재하지 않는다.
  • cat 은, ‘파일’ 이거나 ‘Standard Input’ 만을 입력으로 받아들인다. (man cat: Concatenate FILE(s) to standard output. With no FILE, or when FILE is -, read standard input.)

cat 이 파일이나 Std. Input 만을 받아들이기 때문에, cat "abcd" 를 하면, abcd 라는 파일을 찾지, abcd 라는 문자열을 출력하진 않는다.
이 부분에 대한 자세한 내용은 다음 문서에서.

초보인 나는, 이런 생각을 했다.

  • 먼저, 프로그램 내에서 /tmp/aa.txt 등으로 임시 파일(문자열)을 생성한다.
  • cat 으로 그 파일을 출력한다. (cat /tmp/aa.txt)
  • /tmp/aa.txt 를 삭제한다.

이렇게 하면 안된다는 법은 없다. 저런 저속한 기법을 사용했다고 누가 뭐라할 사람도 없다.

그러나, 저런 경우를 대비해서 Shell Script 에는 문법이 존재하고 있고, 그게 바로 Here Document 이다.

사용법은 이렇다.

command << token
문자열..
...
...
token

내 나이대에서 ‘토큰’이라고 하면 ‘구멍뚫린, 버스용 동전’을 주로 떠올릴 테지만, (요즘 애들은 토큰이라고 하면 뭘 생각하려나) 여기서 token 은 아마도, “an indication, warning, or sign of something (by Collins British Dict.)”를 의미하는 듯 하다.

즉, 이 ‘표시’는 무시하고, 다음 ‘표시’가 다시 나타날 때까지가 실제 데이터라는 뜻이 되겠다.
이 Token 은 아무 글자나 써도 된다. ‘token’ 이라 써도 되고, ‘whatever’ 라 해도 되고, ‘뭐야’도, ‘개판’도 다 된다. 시종이 같기만 하면 된다. (물론 예약어를 쓰면 안된다. (안되겠지?))

그러나, 관습(Common Convention)으로, 또는 타인들과 코드 공유성(?)을 높이기 위해 ‘EOF/_EOF_‘ 등을 많이 사용한다.

실제 코드 사용은 어떻게 하나?
위에서 /tmp/aa.txt 를 사용했다면, 스크립트엔 이렇게 표기된다.

cat /tmp/aa.txt

물론, 그 전에 /tmp/aa.txt 로 임시파일을 생성하는 코드는 생략했다.
반면, Here Document 를 사용한다면,

cat << EOF
Perl
PHP
Ruby
Python
D
OS/JCL
Racket
EOF

이 결과로, Perl 부터 Racket 까지가 출력된다.

위에서 내가 했던 질문을 다시 되짚어보자.

그럼, 여기는 어디고, 문서란 뭘 말하는 걸까?

‘여기’는 코드 내부다. 외부에 문서를 만드는게 아니고, 코드 내부에서 가상 문서를 만든다고 생각하자.
‘문서’는 EOF 로 둘러싸인 문자열을 말한다. 이게 문자열들이 실제 문서같이 취급된다.

문법을 살짝 들여다 보면,
<< 는 EOF 사이에 있는 내용을 Std. Input 으로 cat 에게 전달하라는 뜻이다. < 를 하나만 쓰면 엉뚱한 결과가 나타나니 조심해야 한다. 물론 < 도 Std. Input 이긴 한데, Here Document 문법은 << 라고 써줘야 한다.

또, 이걸 쓰기 위해선 Command 가 Standard Input 을 지원해야 한다. 그렇지 않은 명령을 쓰면 원하던 결과를 얻지 못하니 역시 주의해야 한다.


<< 대신에 <<- 를 쓸 수도 있다. <<- 를 쓰면, 문자열을 들여쓰기 할 수 있다. 따라서 코드를 읽기에 훨씬 도움을 줄 수 있다. 다만, 이때 들여쓰는 문자는 반드시 ‘탭’이라야 한다. 편집기 설정에 따라서, 탭문자를 모두 공백으로 바꾸는 경우도 있는데, 이럴 땐 앞부분을 그대로 공백으로 인식하므로 주의해야 한다.

예를 들어,

cat <<- EOF
    Perl
    PHP
    Ruby
    Python
    D
    OS/JCL
    Racket
EOF

위 공백이 탭(\t)이라면 출력은 다음과 같다.

Perl
PHP
Ruby
Python
D
OS/JCL
Racket

그러나, 공백이 그야말로 공백(\s)이라면, 출력도 들여쓰기가 된다.

   Perl
   PHP
   Ruby
   Python
   D
   OS/JCL
   Racket

이 점을 주의해야 한다.


내 나름대로 정리!

코드에서 문자열로 된 문서가 필요할 때, 코드 내부에 마치 실제 문서가 있는 듯 만들어놓고, 그 가상 문서를 Std. Input 으로 전환해서 입력을 받는 방법. << 와 Token 을 사용한다.

It is a section of a source code file that is treated as if it were a separate file.

Wikepedia


Here Documents 도 Redirection 인데, 이와 비슷한 개념이라 할 수 있는게 Process Substitution 이다.
이쯤되면 마구 헷갈리지만, 어쨌든 자세한 사항은 다른 글에 정리되어 있다.


Here String?

Here Document 와 하는 일은 같다.
다만 축약형이라고나 할까?

Here Document 는 << 를 사용하고, Here String 은 <<< 를 사용한다.
<< 뒤에는 token 내용 token 이 붙지만, <<< 뒤에는 문자열이 바로 붙거나, 아니면 문자열을 담고 있는 변수가 붙는다.
무식한 질문이지만, 문자열이나 변수가 아닌 ‘파일’은 안되나?

파일을 붙일 땐 그냥 < Redirection 을 쓰면 된다. (복잡하게 생각하다보면, 단순한 기본 지식을 잊어버릴 때가 많다.)

예를 들어, “우리나라” 를 Here String 으로 사용하려면 다음과 같이 한다.

cat <<< "우리나라"

변수를 사용하려면, 그냥 변수를 넣어주면 된다. (변수 안에 문자열이 들어있다는 가정)

cat <<< $var
One Comment

안녕하세요. 글 남겨주셔서 고맙습니다.