você pode esclarecer o que você quer dizer com "linha de comando"?
23419 Bart Bart
Estou apenas me perguntando se há uma variável especial dólar que contém a cadeia completa (linha de comando), e não apenas o nome do script e seus argumentos
Mas um bashshell interativo pode aproveitar o mecanismo do histórico e a DEBUGarmadilha para "contar" os comandos nos quais executa a linha de comando completa da qual fazem parte por meio de uma variável de ambiente:
Embora útil, este só funciona em Linux - não outra Unixes
Scott Earle
2
Ao usar /proc/self/fd, você pode ver se está em um pipeline e também um ID para o pipe. Se você /proc/\*/fdprocurar o tubo correspondente, poderá encontrar o PID da outra extremidade do tubo. Com o PID, você pode ler /proc/$PID/cmdlinee repetir o processo em seus descritores de arquivo para descobrir o que é canalizado.
$ cat | cat | cat &
$ ps
PID TTY TIME CMD6942 pts/1600:00:00 cat6943 pts/1600:00:00 cat6944 pts/1600:00:00 cat7201 pts/1600:00:00 ps20925 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
Além disso, se você tiver sorte, os diferentes comandos no pipeline receberão PIDs consecutivos, o que facilitará um pouco.
Na verdade, não tenho um script para fazer isso, mas provei o conceito.
Aqui, ele $BASH_COMMANDé expandido enquanto o expurga até o evalbit da string, e a string do resultado é "capturada instantaneamente" em uma $CMDvariável auxiliar .
Obrigado por suas respostas. Eu testei coisas diferentes e vim para o seguinte script de teste:
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
Testes:
$ ./test.sh test1Command 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 | catCommand 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 test3Command 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.
O histórico da linha de comando está funcionando apenas sem um Shebang na linha superior do script. Não sei se isso funcionará de maneira confiável e em outros sistemas também.
Não consegui suprimir a saída do "readlink" (ou "arquivo", como sugerido pela Archemar), quando o status foi bem-sucedido ("/ dev / pts / 3"). A saída da tubulação para / dev / null ou para uma variável levaria ao mau funcionamento. Portanto, isso não seria uma opção para mim em um script.
A verificação TTY mencionada por muru é fácil e talvez já seja suficiente para alguns casos de uso.
Edit: Meu crédito vai para mosvy, porque a questão era como obter a linha de comando completa e não apenas para determinar se o script está em um cano. Eu gosto da parte simples "fc -nl -0" em sua resposta, porque nenhuma configuração adicional do sistema é necessária. Não é uma solução 100%, mas é apenas para meu uso pessoal e, portanto, suficiente. Obrigado a todos pela ajuda.
A verificação TTY também pode ser feito para stdin: [ -t 0 ]. Portanto, você pode verificar se stdin ou stdout não é um TTY e proceder de acordo.
Muru
Se você quiser saber se o stdout é um pipe, no Linux você pode usar if [ -p /dev/stdout ]; ...(assim readlink /proc/self/fd/..não funciona no BSD).
mosvy
2
O script precisa funcionar IMNSHO. o echo -equase certamente não quer o -e. Você precisa de mais casos de teste, redirecionando para um arquivo, sendo chamado por dentro $(...). No entanto, exorto-o a considerar se é uma boa ideia. Programas como os lsque alteram sua saída, dependendo se estão sendo enviados para um tty ou um pipe, são irritantes de usar.
[ -t 1 ]
unix.stackexchange.com/a/401938/70524Respostas:
Não há como fazer isso em geral .
Mas um
bash
shell interativo pode aproveitar o mecanismo do histórico e aDEBUG
armadilha para "contar" os comandos nos quais executa a linha de comando completa da qual fazem parte por meio de uma variável de ambiente:fonte
não
O bash (ou seu shell) bifurcará dois comandos distintos.
test.sh arg1
grep "xyz"
test.sh
não sabia sobre seguir grep.no entanto, você pode saber que está "dentro" de um tubo testando
/proc/self/fd/1
test.sh
que funcionam como
(Editar) veja o comentário de muru sobre saber se você está em um cano.
fonte
Ao usar
/proc/self/fd
, você pode ver se está em um pipeline e também um ID para o pipe. Se você/proc/\*/fd
procurar o tubo correspondente, poderá encontrar o PID da outra extremidade do tubo. Com o PID, você pode ler/proc/$PID/cmdline
e repetir o processo em seus descritores de arquivo para descobrir o que é canalizado.Além disso, se você tiver sorte, os diferentes comandos no pipeline receberão PIDs consecutivos, o que facilitará um pouco.
Na verdade, não tenho um script para fazer isso, mas provei o conceito.
fonte
Outra maneira pode ser acessando a
$BASH_COMMAND
variável automática, mas é inerentemente volátil e difícil de capturar o valor desejado.Eu acho que você só poderia pegá-lo através de um
eval
, o que também envolve chamar suas linhas de comando de uma maneira especial, como em:Aqui, ele
$BASH_COMMAND
é expandido enquanto o expurga até oeval
bit da string, e a string do resultado é "capturada instantaneamente" em uma$CMD
variável auxiliar .Pequeno exemplo:
Naturalmente, também pode funcionar (na verdade melhor) ao invocar scripts por exemplo
sh -c
oubash -c
, como em:Aqui sem limpar a variável.
fonte
Obrigado por suas respostas. Eu testei coisas diferentes e vim para o seguinte script de teste:
test.sh:
Testes:
O histórico da linha de comando está funcionando apenas sem um Shebang na linha superior do script. Não sei se isso funcionará de maneira confiável e em outros sistemas também.
Não consegui suprimir a saída do "readlink" (ou "arquivo", como sugerido pela Archemar), quando o status foi bem-sucedido ("/ dev / pts / 3"). A saída da tubulação para / dev / null ou para uma variável levaria ao mau funcionamento. Portanto, isso não seria uma opção para mim em um script.
A verificação TTY mencionada por muru é fácil e talvez já seja suficiente para alguns casos de uso.
Edit: Meu crédito vai para mosvy, porque a questão era como obter a linha de comando completa e não apenas para determinar se o script está em um cano. Eu gosto da parte simples "fc -nl -0" em sua resposta, porque nenhuma configuração adicional do sistema é necessária. Não é uma solução 100%, mas é apenas para meu uso pessoal e, portanto, suficiente. Obrigado a todos pela ajuda.
fonte
[ -t 0 ]
. Portanto, você pode verificar se stdin ou stdout não é um TTY e proceder de acordo.if [ -p /dev/stdout ]; ...
(assimreadlink /proc/self/fd/..
não funciona no BSD).echo -e
quase certamente não quer o-e
. Você precisa de mais casos de teste, redirecionando para um arquivo, sendo chamado por dentro$(...)
. No entanto, exorto-o a considerar se é uma boa ideia. Programas como osls
que alteram sua saída, dependendo se estão sendo enviados para um tty ou um pipe, são irritantes de usar.