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-command
를 sh -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