ksh에 스크립트가 있습니다. 명령줄에서 리디렉션이 있는지 여부에 따라 를 전달합니다 exec 1>file
. 스크립트를 호출하는 명령이 출력을 리디렉션한 경우 스크립트 자체 내에서 이를 어떻게 테스트할 수 있습니까?
스크립트의 PID에서 $@
, $*
, $0
, 및 a를 사용해 보았지만 ps
(셔뱅과 함께) 리디렉션이 나타나지 않습니다.
이 예에서 스크립트는 AIX에서 실행됩니다.
답변1
AIX에서는 stdout 파일 설명자를 에서 사용할 수 /proc/$$/fd/1
있으므로 일반 파일인지 테스트할 수 있습니다.
if [ -f "/proc/$$/fd/1" ]
then
echo stdout has already been redirected
else
echo redirecting stdout
exec 1>file
echo some output
fi
/bin/sh는 /bin/ksh에 하드 링크되어 있으므로 두 쉘 모두에서 동일한 동작을 얻습니다.
필요한 경우 stdout이 /dev/null로 리디렉션되었는지 별도로 테스트할 수 있습니다.
if [ "/proc/$$/fd/1" -ef /dev/null ]; then : ...; fi
답변2
일반적으로 말하면 할 수 없습니다. 리디렉션은 실행 명령에 대한 인수로 표시되지 않습니다. 그렇게 하더라도 모든 경우에 스크립트 출력이 어디로 가는지 알 수 없습니다. 다음 두 가지를 고려하십시오.
bash -c 'somecmd > /dev/null; othercmd'
그리고
bash -c 'somecmd; othercmd' > /dev/null
첫 번째 경우에는 의 출력이 somecmd
로 리디렉션되지만 , 두 번째 경우에는 및 을 /dev/null
포함한 전체 셸의 출력이 리디렉션됩니다 . 두 번째 경우의 명령줄을 보면 출력이 어떻게 리디렉션되는지 알 수 없습니다.somecmd
othercmd
somecmd
즉, Bash의 DEBUG
트랩은 이러한 목적에 유용한 것으로 보입니다.
$ trap 'export CMDLINE=$BASH_COMMAND' DEBUG
$ env 2>/dev/null |grep CMD
CMDLINE=env 2> /dev/null
트랩은 실행할 명령을 내보냅니다 CMDLINE
. 의 출력에 해당 명령이 표시되므로 해당 명령이 내보내지는 것을 볼 수 있습니다 env
. 전체 파이프라인은 표시되지 않고 단일 명령만 표시됩니다.
즉, 대부분의 경우 사용자의 리디렉션을 추측하는 것보다 문제를 처리하는 더 나은 방법이 있습니다. 많은 명령은 출력이 터미널로 전송되는지 확인하고 그에 따라 동작을 변경합니다.
stdout이 터미널인지 확인하려면 다음을 사용할 수 있습니다 [ -t 1 ]
.
$ if [ -t 1 ]; then echo terminal; else echo not terminal; fi |cat
not terminal
이는 출력이 터미널에 도달하지 않아 가정에 따라 사용자에게 도달하지 않는 경우 특정 대화형 기능이나 외부 출력을 비활성화하는 데 가장 자주 사용됩니다.
파일 설명자가 터미널을 가리키는지 테스트하는 것만으로는 충분하지 않은 경우 가장 간단한 접근 방식은 프로그램에 추가 인수를 전달하여 실행할 모드를 알려주는 것입니다. 즉, 리디렉션에 신경 쓰지 않고 프로그램이 로 시작하면 한 가지 작업을 수행하고 someprog --mode=cron
로 시작하면 다른 작업을 someprog --mode=batch
수행하며 인수 없이 시작되면 대화형으로 실행되도록 합니다 --mode
. (대화형 또는 명령줄 모드를 기본값으로 설정하면 사용자가 --mode=commandline
수동으로 실행할 때마다 수동으로 입력할 필요가 없습니다.)
답변3
내 테스트에서는 5.0.3(1)-release (x86_64-pc-linux-gnu)
Linux(Debian 10.12)에서 Bash 5(GNU bash, 버전)를 사용하여 테스트가 작동했습니다 [ -p
.
- 스크립트를 고려해보세요
test.sh
#!/bin/bash ls -lah /proc/$$/fd/1 if [ -p "/proc/$$/fd/1" ]; then echo "pipe"; else echo "nopipe"; fi exec 1> >( cat ) 2>&1 ls -lah /proc/$$/fd/1 if [ -p "/proc/$$/fd/1" ]; then echo "pipe"; else echo "nopipe"; fi
- 리디렉션 없이 또는 리디렉션을 사용하여 스크립트를 실행합니다.
$ ./test.sh lrwx------ 1 [...] /proc/123/fd/1 -> /dev/pts/2 nopipe l-wx------ 1 [...] /proc/123/fd/1 -> pipe:[12345] pipe $ ./test.sh | cat l-wx------ 1 [...] /proc/124/fd/1 -> pipe:[12346] pipe l-wx------ 1 [...] /proc/124/fd/1 -> pipe:[12347] pipe