例如命令行:
test.sh arg1 | grep "xyz"
是否可以在 bash 脚本 test.sh 中获取包括以下 grep 的完整命令行?
答案1
不
bash(或你的 shell)将分叉两个不同的命令。
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]
(编辑)参见穆鲁的评论关于知道你是否在管道上。
你不需要知道你是否正处于这样的困境中。只需检查输出是否为 TTY。
[ -t 1 ]
https://unix.stackexchange.com/a/401938/70524
答案2
没有办法做到这一点一般来说。
但是交互式bash
shell 可以利用历史机制和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
自动变量,但它本质上是不稳定的并且很难捕获所需的值。
我认为你只能通过 an 来捕获它eval
,这还涉及以特殊方式调用命令行,例如:
CMD="${BASH_COMMAND##* eval }" eval './test.sh arg1 | grep "xyz"'
Here$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
$
当然,它也可以在通过 egsh -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
$
这里没有清除变量。