¿Puedes aclarar qué quieres decir con "línea de comando"?
Bart
Me pregunto si hay una variable especial en dólares que contiene la cadena completa (la línea de comandos), no sólo el nombre del script y sus argumentos
hellcode
2
¿Cuál sería su caso de uso para hacer esto?
Kusalananda
99
@hellcode no necesita saber si está en una tubería para eso. Simplemente verifique si la salida es un TTY. [ -t 1 ]unix.stackexchange.com/a/401938/70524
Pero un bashshell interactivo puede aprovechar el mecanismo del historial y la DEBUGtrampa para "decir" a los comandos que ejecuta la línea de comandos completa de la que forman parte a través de una variable de entorno:
Si bien es útil, esto solo funciona en Linux, no en otros Unixes
Scott Earle el
2
Al usar /proc/self/fd, puede ver si está en una tubería, así como una ID para la tubería. Si itera /proc/\*/fdbuscando la tubería coincidente, puede encontrar el PID del otro extremo de la tubería. Con el PID, puede leer /proc/$PID/cmdliney repetir el proceso en sus descriptores de archivo para encontrar en qué se canaliza.
$ cat | cat | cat &
$ ps
PID TTY TIME CMD
6942 pts/1600:00:00 cat
6943 pts/1600:00:00 cat
6944 pts/1600:00:00 cat
7201 pts/1600:00:00 ps
20925 pts/1600:00:00 bash
$ ls -l /proc/6942/fd
lrwx------.1 tim tim 64Jul2419:590->/dev/pts/16
l-wx------.1 tim tim 64Jul2419:591->'pipe:[49581130]'
lrwx------.1 tim tim 64Jul2419:592->/dev/pts/16
$ ls -l /proc/6943/fd
lr-x------.1 tim tim 64Jul2419:590->'pipe:[49581130]'
l-wx------.1 tim tim 64Jul2419:591->'pipe:[49581132]'
lrwx------.1 tim tim 64Jul2419:592->/dev/pts/16
$ ls -l /proc/6944/fd
lr-x------.1 tim tim 64Jul2419:590->'pipe:[49581132]'
lrwx------.1 tim tim 64Jul2419:591->/dev/pts/16
lrwx------.1 tim tim 64Jul2419:592->/dev/pts/16
Además, si tiene suerte, los diferentes comandos en la tubería obtendrán PID consecutivos que lo harán un poco más fácil.
En realidad no tengo un guión para hacer esto, pero he demostrado el concepto.
Aquí $BASH_COMMANDse expande al mismo tiempo que se purga hasta el evalbit de cadena, y la cadena de resultado se "captura" en una $CMDvariable auxiliar .
Gracias por tus respuestas. He probado diferentes cosas y llegué al siguiente script de prueba:
test.sh:
hist=`fc -nl -0`# remove leading and trailing whitespaces
hist="$(echo "${hist}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
echo "Command line from history: '$hist'"if[-t 1];then
echo "Direct output to TTY, no pipe involved."else
echo "No TTY, maybe a piped command."fiif[-p /dev/stdout ];then
echo "stdout is a pipe."else
echo "stdout is not a pipe."fi
readlink -e /proc/self/fd/1
rst=$?if[ $rst -eq 0];then
echo "Readlink test status okay, no pipe involved."else
echo "Readlink test status error $rst, maybe a piped command."fi
Pruebas:
$ ./test.sh test1
Command line from history:'./test.sh test1'Direct output to TTY, no pipe involved.
stdout is not a pipe./dev/pts/3Readlink test status okay, no pipe involved.
$ ./test.sh test2 | cat
Command line from history:'./test.sh test2 | cat'No TTY, maybe a piped command.
stdout is a pipe.Readlink test status error 1, maybe a piped command.
$ echo "another command before pipe doesn't matter"|./test.sh test3
Command line from history:'echo "another command before pipe doesn't matter" | ./test.sh test3'
Direct output to TTY, no pipe involved.
stdout is not a pipe.
/dev/pts/3
Readlink test status okay, no pipe involved.
El historial de la línea de comandos solo funciona sin un Shebang en la línea superior del script. No sé si esto funcionará de manera confiable y también en otros sistemas.
No pude suprimir la salida de "readlink" (o "archivo" como se sugiere desde Archemar), cuando el estado fue exitoso ("/ dev / pts / 3"). La salida de tubería a / dev / null o a una variable conduciría a un mal funcionamiento. Entonces, esta no sería una opción para mí en un script.
La verificación de TTY que mencionó muru es fácil y tal vez ya sea suficiente para algunos casos de uso.
Editar: Mi crédito es para mosvy, porque la pregunta era cómo obtener la línea de comando completa y no solo para determinar si el script está en curso. Me gusta la parte simple "fc -nl -0" en su respuesta, porque no se necesita más configuración del sistema. No es una solución al 100 por ciento, pero es solo para mi uso personal y, por lo tanto, suficiente. Gracias a todos los demás por vuestra ayuda.
La comprobación de TTY también se puede hacer por la entrada estándar: [ -t 0 ]. Por lo tanto, puede verificar si stdin o stdout no es un TTY y proceder en consecuencia.
muru
Si desea saber si el stdout es una tubería, en Linux puede usarlo if [ -p /dev/stdout ]; ...(así como readlink /proc/self/fd/..esto no funciona en BSD).
mosvy
2
El script necesita trabajar IMNSHO. es echo -ecasi seguro que no quiere el -e. Necesita más casos de prueba, redirigir a un archivo, ser invocado dentro $(...). Sin embargo, le recomiendo que considere si es una buena idea. Los programas como los lsque cambian su salida dependiendo de si están saliendo a un tty o una tubería son molestos de usar.
[ -t 1 ]
unix.stackexchange.com/a/401938/70524Respuestas:
No hay forma de hacerlo en general .
Pero un
bash
shell interactivo puede aprovechar el mecanismo del historial y laDEBUG
trampa para "decir" a los comandos que ejecuta la línea de comandos completa de la que forman parte a través de una variable de entorno:fuente
No
bash (o su shell) bifurcará dos comandos distintos.
test.sh arg1
grep "xyz"
test.sh
No podría saber acerca de seguir grep.Sin embargo, puede saber que está "dentro" de una tubería al probar
/proc/self/fd/1
test.sh
que corren como
(Editar) vea el comentario de muru sobre saber si está en una tubería.
fuente
Al usar
/proc/self/fd
, puede ver si está en una tubería, así como una ID para la tubería. Si itera/proc/\*/fd
buscando la tubería coincidente, puede encontrar el PID del otro extremo de la tubería. Con el PID, puede leer/proc/$PID/cmdline
y repetir el proceso en sus descriptores de archivo para encontrar en qué se canaliza.Además, si tiene suerte, los diferentes comandos en la tubería obtendrán PID consecutivos que lo harán un poco más fácil.
En realidad no tengo un guión para hacer esto, pero he demostrado el concepto.
fuente
Otra forma podría ser acceder a la
$BASH_COMMAND
variable automática, pero es inherentemente volátil y difícil de atrapar el valor deseado.Creo que solo puedes atraparlo solo a través de un
eval
, lo que también implica invocar tus líneas de comando de una manera especial, como en:Aquí
$BASH_COMMAND
se expande al mismo tiempo que se purga hasta eleval
bit de cadena, y la cadena de resultado se "captura" en una$CMD
variable auxiliar .Pequeño ejemplo:
Naturalmente, también puede funcionar (en realidad mejor) al invocar scripts por ej.
sh -c
Obash -c
, como en:Aquí sin purgar la variable.
fuente
Gracias por tus respuestas. He probado diferentes cosas y llegué al siguiente script de prueba:
test.sh:
Pruebas:
El historial de la línea de comandos solo funciona sin un Shebang en la línea superior del script. No sé si esto funcionará de manera confiable y también en otros sistemas.
No pude suprimir la salida de "readlink" (o "archivo" como se sugiere desde Archemar), cuando el estado fue exitoso ("/ dev / pts / 3"). La salida de tubería a / dev / null o a una variable conduciría a un mal funcionamiento. Entonces, esta no sería una opción para mí en un script.
La verificación de TTY que mencionó muru es fácil y tal vez ya sea suficiente para algunos casos de uso.
Editar: Mi crédito es para mosvy, porque la pregunta era cómo obtener la línea de comando completa y no solo para determinar si el script está en curso. Me gusta la parte simple "fc -nl -0" en su respuesta, porque no se necesita más configuración del sistema. No es una solución al 100 por ciento, pero es solo para mi uso personal y, por lo tanto, suficiente. Gracias a todos los demás por vuestra ayuda.
fuente
[ -t 0 ]
. Por lo tanto, puede verificar si stdin o stdout no es un TTY y proceder en consecuencia.if [ -p /dev/stdout ]; ...
(así comoreadlink /proc/self/fd/..
esto no funciona en BSD).echo -e
casi seguro que no quiere el-e
. Necesita más casos de prueba, redirigir a un archivo, ser invocado dentro$(...)
. Sin embargo, le recomiendo que considere si es una buena idea. Los programas como losls
que cambian su salida dependiendo de si están saliendo a un tty o una tubería son molestos de usar.