2019년 10월 17일 목요일

Bash에서 탭(tab)을 표현하기 어려운 경우의 해결 방법

'\t'로 표현되는 tab 문자는 주의를 기울이지 않으면 화면에서 출력하기가 어렵다. Perl에서는 따옴표로 둘러치면 되지만 bash에서는 이것으로는 안된다. 그래서 echo 명령어에서는 -e 옵션을 통해서 백슬래쉬(\)로 이스케이프된 문자의 번역을 하도록 만든다.

$ echo 'hello\tworld'
hello\tworld
$ echo "hello\tworld"
hello\tworld
$ echo -e 'hello\tworld'
hello world
$ echo -e "hello\tworld"
hello world

이에 대한 보다 근본적인 해결 방법이 있다. 바로 $'string'을 쓰는 것이다. $'\t'라고만 하거나 혹은 문자열 전체를 $'..'로 둘러치거나 결과는 같다.

$ echo hello$'\t'world
hello world
$ echo $'hello\tworld'
hello world

Bash reference manual의 ANSI-C quoting 항목에서는 다음과 같이 설명하였다.
The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard.
이러한 요령을 알고 있으면 텍스트 파일을 처리하는 유틸리티에서 탭을 구분자로 지정해 줄 때 발생하는 오류에 대처할 수 있다. sortjoin 명령어에서는 -t SEP 옵션을 사용하여 구분자(SEP은 구분자로 쓰려는 문자)를 설정하는데, 탭을 구분자로 정의하려면 -t$'\t'라고 하는 것이 안전하다. 물론 이것은 bash에서 그렇다는 뜻이다.

예를 들어 다음과 같이 test라는 파일을 두번째 컬럼 기준으로 정렬하는 경우를 생각해 보자. 구분자로는 탭을 사용하고자 한다. line 바로 앞에 오는 스페이스를 구분자로 써서는 안되는 것이다. 다음 사례 중 의도한 결과가 나온 것은 어느것인가?

$ cat test
[first line] 1 A
[third line] 3 C
[second line] 2 B
$ sort -t \t -k 2 test
second 1-line: 2 A
first 2-line: 3 C
third 3-line: 1 B
$ sort -t\t -k 2 test
second 1-line: 2 A
first 2-line: 3 C
third 3-line: 1 B
$ sort -t '\t' -k 2 test
sort: multi-character tab `\\t'
$ sort -t'\t' -k 2 test
sort: multi-character tab `\\t'
$ sort -t "\t" -k 2 test
sort: multi-character tab `\\t'
$ sort -t"\t" -k 2 test
sort: multi-character tab `\\t'
$ sort -t$'\t' -k2 test
third 3-line: 1 B
second 1-line: 2 A
first 2-line: 3 C
$ sort -t $'\t' -k2 test
third 3-line: 1 B
second 1-line: 2 A
first 2-line: 3 C

-t \t 또는 -t\t라고 입력한 것은 오류 메시지를 출력하지는 않았으나 원하는 결과가 아님에 주의해야 한다.

첨언하자면 나는 리눅스 명령어의 옵션과 그에 부속되는 설정어를 하나로 붙여서 쓰는 것을 그다지 좋아하지 않는다. 여러 옵션을 하나로 붙이는 것, 즉 ls -l -t를 ls -lt로 쓰는 것은 지극히 정상적이고 일상적인 방법이다. 그러나 sort -k 2 file을 sort -k2 file로 쓰는 것은 선호하지 않는다. -k -2를 축약해서 -k2라고 표현하는 것은 절대 아니기 때문이다.

awk의 입력 필드 정의 옵션인 -F fs(field separator)에서 는 $'\t' 형식으로 일부러 인용 처리하지 않아도 된다는 점이 장점이다. 그저 -F '\t' 또는 -F "\t"라고만 해도 된다. -F '\t'라 해도 작동은 하지만, awk의 표준 사용법은 awk 'command' 이므로 -F에 이어서 공급해야 하는 field separator 자체를 작은 따옴표로 둘러치는 것은 별로 바람직하지 않다고 생각한다. 같은 이유에서 작은 따옴표를 사용하게 되는 -F $'\t' 표현도 썩 내키지는 않는다.

화면에 오류 메시지가 나오지 않았다고 해서 내가 짠 스크립트가 항상 제대로 돌아가고 있다고 착각하지는 말자.

댓글 1개:

Anneli Jäätteenmäki :
블로그 관리자가 댓글을 삭제했습니다.