예를 들어 명령줄은 다음과 같습니다.
test.sh arg1 | grep "xyz"
bash 스크립트 test.sh에서 다음 grep을 포함한 전체 명령줄을 얻을 수 있습니까?
답변1
아니요
bash(또는 쉘)는 두 가지 다른 명령을 분기합니다.
test.sh arg1
grep "xyz"
test.sh
grep을 따르는 방법을 모릅니다.
그러나 테스트를 통해 파이프라인 "내부"에 있음을 알 수 있습니다./proc/self/fd/1
테스트 파일
#!/bin/bash
file /proc/self/fd/1
작동 모드는 다음과 같습니다.
> ./test.sh
/proc/self/fd/1: symbolic link to /dev/pts/0
> ./test.sh | cat
/proc/self/fd/1: broken symbolic link to pipe:[25544239]
(편집자) 참조Mulu의 코멘트당신이 파이프라인에 있는지 아는 것에 대해.
당신이 그런 곤경에 처해 있는지 알 필요는 없습니다. 출력이 TTY인지 확인하십시오.
[ -t 1 ]
https://unix.stackexchange.com/a/401938/70524
답변2
이렇게 할 방법이 없습니다일반적으로 말하면.
그러나 대화형 bash
쉘은 히스토리 메커니즘과 트랩을 활용하여 DEBUG
환경 변수를 통해 실행하도록 전체 명령줄을 "알려줄" 수 있습니다.
$ trap 'export LC=$(fc -nl -0); LC=${LC#? }' DEBUG
$ sh -c 'printf "last_command={%s}\n" "$LC"' | cat; true
last_command={sh -c 'printf "last_command={%s}\n" "$LC"' | cat; true}
답변3
를 사용하면 /proc/self/fd
파이프라인에 있는지 여부와 파이프라인의 ID를 확인할 수 있습니다. 일치하는 파이프를 반복하면 /proc/\*/fd
파이프 반대쪽 끝의 PID를 찾을 수 있습니다. PID를 사용하면 /proc/$PID/cmdline
파일 설명자에서 프로세스를 읽고 반복하여 파이프 대상을 찾습니다.
$ cat | cat | cat &
$ ps
PID TTY TIME CMD
6942 pts/16 00:00:00 cat
6943 pts/16 00:00:00 cat
6944 pts/16 00:00:00 cat
7201 pts/16 00:00:00 ps
20925 pts/16 00:00:00 bash
$ ls -l /proc/6942/fd
lrwx------. 1 tim tim 64 Jul 24 19:59 0 -> /dev/pts/16
l-wx------. 1 tim tim 64 Jul 24 19:59 1 -> 'pipe:[49581130]'
lrwx------. 1 tim tim 64 Jul 24 19:59 2 -> /dev/pts/16
$ ls -l /proc/6943/fd
lr-x------. 1 tim tim 64 Jul 24 19:59 0 -> 'pipe:[49581130]'
l-wx------. 1 tim tim 64 Jul 24 19:59 1 -> 'pipe:[49581132]'
lrwx------. 1 tim tim 64 Jul 24 19:59 2 -> /dev/pts/16
$ ls -l /proc/6944/fd
lr-x------. 1 tim tim 64 Jul 24 19:59 0 -> 'pipe:[49581132]'
lrwx------. 1 tim tim 64 Jul 24 19:59 1 -> /dev/pts/16
lrwx------. 1 tim tim 64 Jul 24 19:59 2 -> /dev/pts/16
또한 운이 좋다면 파이프라인의 다양한 명령이 연속적인 PID를 얻게 되므로 작업이 좀 더 쉬워질 것입니다.
실제로 이 작업을 수행할 스크립트는 없지만 개념을 시연했습니다.
답변4
또 다른 접근 방식은 자동 변수에 액세스하는 것일 수 있지만 $BASH_COMMAND
이는 본질적으로 불안정하고 원하는 값을 캡처하기 어렵습니다.
eval
제 생각 에는 다음과 같은 특별한 방법으로 명령줄을 호출하는 것을 통해서만 이를 잡을 수 있다고 생각합니다 .
CMD="${BASH_COMMAND##* eval }" eval './test.sh arg1 | grep "xyz"'
여기서는 $BASH_COMMAND
확장되어 eval
문자열의 비트도 지워지므로 결과 문자열이 보조 $CMD
변수에 "스냅샷"됩니다.
작은 예:
$ cat test.sh
#!/bin/sh
printf 'you are running %s\n' "$CMD"
sleep 1
echo bye bye
$
$ CMD="${BASH_COMMAND##* eval }" eval './test.sh | { grep -nH "."; }'
(standard input):1:you are running './test.sh | { grep -nH "."; }'
(standard input):2:bye bye
$
물론 sh -c
다음과 같은 방법으로 스크립트를 호출할 때도 작동합니다(실제로는 더 좋습니다) bash -c
.
$
$ CMD="${BASH_COMMAND}" sh -c './test.sh | { grep -nH "."; }'
(standard input):1:you are running CMD="${BASH_COMMAND}" sh -c './test.sh | { grep -nH "."; }'
(standard input):2:bye bye
$
여기서는 지워진 변수가 없습니다.