Is it possible to access the complete command line including pipes in a bash script?
no
bash (or your shell) will fork two distinct commands.
test.sh arg1
grep "xyz"
test.sh
couldn't know about following grep.
you might however know you are "inside" a pipe by testing /proc/self/fd/1
test.sh
#!/bin/bash
file /proc/self/fd/1
which run as
> ./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]
(Edit) see muru’s comment about knowing if you are on a pipe.
you don't need to know if you're in a pipe for that. Just check if output is a TTY.
[ -t 1 ]
https://unix.stackexchange.com/a/401938/70524
There is no way to do that in general.
But an interactive bash
shell can leverage the history mechanism and the DEBUG
trap to "tell" the commands it runs the complete command line they're part of via an environment variable:
$ 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}
By using /proc/self/fd
, you can see if you're in a pipeline as well as an ID for the pipe. If you iterate through /proc/\*/fd
looking for the matching pipe, you can find the PID of the other end of the pipe. With the PID, you can then read /proc/$PID/cmdline
as well as repeat the process on its file descriptors to find what it's piped into.
$ 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
Also if you're lucky, the different commands in the pipeline will get consecutive PIDs which will make it a bit easier.
I don't actually have a script to do this, but I have proved the concept.