Macros for running shell commands

기본적으로 매크로에 () 가 없으면 매크로로 인식되지 않습니다.

Determining the platform

현재 m4 가 실행되는 platform 을 알 수 있게 다음과 같은 optional builtin 매크로가 제공됩니다. 매크로가 정의되어 있는지는 ifdef 을 이용해 테스트할 수 있고, 정의되어 있을 경우 확장은 empty 스트링이 됩니다. 다음은 linux 에서 실행한 결과인데 __gnu____unix__ 매크로가 설정된 것을 알 수 있습니다.

$ m4 <<\@
Optional builtin: __gnu__             
Optional builtin: __os2__
Optional builtin: os2
Optional builtin: __unix__
Optional builtin: unix
Optional builtin: __windows__
Optional builtin: windows
@

Optional builtin:                 <---- empty string
Optional builtin: __os2__
Optional builtin: os2
Optional builtin:                 <---- empty string
Optional builtin: unix
Optional builtin: __windows__
Optional builtin: windows
-------------------------------

$ m4 <<\@
define(`provided', `0')
ifdef(`__unix__', `define(`provided', incr(provided))')

provided
@

1

syscmd

syscmd ( shell-command )
매크로의 확장 결과는 void 입니다.

인수로 주어진 shell-commandsh -c 을 이용해 실행시킵니다. 이때 stdin, stdout, stderr 는 현재 실행 중인 m4 와 같습니다. 매크로의 확장 결과는 void 이므로 shell-command 의 출력을 매크로 값으로 사용하려면 esyscmd 매크로를 사용해야 합니다.

esyscmd

esyscmd ( shell-command )

esyscmd 매크로의 확장 결과는 shell-command 의 stdout 값이 됩니다. 따라서 매크로를 정의할 때 값으로 사용할 수 있습니다. stderr 출력은 값에 포함되지 않습니다.

명령 출력 결과 trailing newline 을 제거하려면 다음과 같이하면 됩니다.

$ m4 <<\@        
define(`current_date', `esyscmd(`date')')
{{ current_date }}
@

{{ Fri Jul 31 13:10:48 KST 2020     <---- newline 이 포함된다.
 }}

$ m4 <<\@        
define(`current_date', `esyscmd(`date | sed -Ez "s/\\n+$//"')')
{{ current_date }}
@

{{ Fri Jul 31 13:10:52 KST 2020 }}

기본적으로 esyscmd 매크로 확장 결과는 quote 이 되지 않기 때문에 shell-command 의 출력에 매칭되는 매크로가 존재할 경우 확장될 수 있습니다. 다음을 보면 KST 매크로가 매칭이 되어 date 명령의 출력이 XXX 로 변경된 것을 볼 수 있습니다.

$ m4 <<\@        
define(`KST', `XXX')
define(`current_date', `esyscmd(`date | sed -Ez "s/\\n+$//"')')
{{ current_date }}
@

{{ Fri Jul 31 05:11:21 XXX 2020 }}       # KST 가 XXX 로 변경됨.

이것을 방지하려면 다음과 같이 shell-command 의 출력에 m4 quotes 을 추가해 주면 됩니다.

$ m4 <<\@        
define(`KST', `XXX')              
define(`current_date', `esyscmd(`date | sed -Ez -e "s/\\n+$//" -e "s/^/\`/;s/$/'/"')')
{{ current_date }}                 # sed 스크립트 작성에 double quotes 이 사용됐으므로
@                                  # \\n 와 \` (명령치환) 를 escape 해야합니다.

{{ Fri Jul 31 05:12:22 KST 2020 }}

sysval

syscmd, esyscmd 매크로에 의해 실행된 shell-command 의 종료 상태 값입니다. 기본값은 0 입니다.

$ m4 <<\@                                  $ m4 <<\@
syscmd(`date')                             syscmd(`date -@')
sysval                                     sysval
@                                          @
Thu Jul 30 20:12:38 KST 2020               date: invalid option -- '@'
                                           Try 'date --help' for more information.
0    # 정상 종료                                     
                                           1     # 오류

mkstemp

mkstemp ( Template )

shell 의 mktemp 명령처럼 임시파일을 만들어주는 매크로입니다. Template 을 지정하지 않으면 기본적으로 현재 디렉토리에 생성합니다. ( 확장 결과는 quote 이 됩니다.)

$ m4 <<\@                               
mkstemp()
mkstemp(`/tmp/XXXXXXXXXX')
mkstemp(`/tmp/foo-XX')
mkstemp(`/tmp/foo-')
@
kq9VZK
/tmp/XXXXh4h8SK
/tmp/foo-ePf8cK
/tmp/foo-rX01nL

$ ls ./kq9VZK /tmp/XXXXh4h8SK /tmp/foo-*
./kq9VZK  /tmp/XXXXh4h8SK  /tmp/foo-ePf8cK  /tmp/foo-rX01nL

Template 에 사용되는 X 의 개수는 6 개로 정해져 있습니다. 그러므로 다음과 같이 XX 두 개를 사용해도 최종 결과는 랜덤 문자가 6 개가 됩니다.

$ m4 <<\@
maketemp(`foo-XX')
ifelse( esyscmd(`echo \`foo-??????\''), `foo-??????', `no file', `created')
@

foo-iDCkBt        # echo 명령에 사용된 \` 와 \' 는 
created           # esyscmd 매크로 확장 결과에 m4 quotes 을 추가하기 위한 것입니다.
$ m4 <<\@                               
define(`file1', mkstemp(`foo-XX'))dnl
define(`file2', mkstemp(`foo-XXXXXX'))dnl

ifelse( len(defn(`file1')), len(defn(`file2')), `same length', `different')
ifelse( defn(`file1'), defn(`file2'), `same', `different file')

syscmd(`rm 'defn(`file1') defn(`file2'))
sysval
@

same length
different file
0