pouvez-vous clarifier ce que vous entendez par «ligne de commande»?
Bart
Je me demande simplement s'il existe une variable dollar spéciale qui contient la chaîne complète (la ligne de commande), pas seulement le nom du script et ses arguments
hellcode
2
Quel serait votre cas d'utilisation pour cela?
Kusalananda
9
@hellcode vous n'avez pas besoin de savoir si vous êtes dans le coup pour ça. Vérifiez simplement si la sortie est un ATS. [ -t 1 ]unix.stackexchange.com/a/401938/70524
Mais un bashshell interactif peut tirer parti du mécanisme d'historique et du DEBUGpiège pour "dire" aux commandes qu'il exécute la ligne de commande complète à laquelle ils appartiennent via une variable d'environnement:
Bien qu'utile, cela ne fonctionne que sur Linux - pas sur les autres Unix
Scott Earle
2
En utilisant /proc/self/fd, vous pouvez voir si vous êtes dans un pipeline ainsi qu'un ID pour le tuyau. Si vous parcourez la /proc/\*/fdrecherche du tuyau correspondant, vous pouvez trouver le PID de l'autre extrémité du tuyau. Avec le PID, vous pouvez ensuite lire /proc/$PID/cmdlineet répéter le processus sur ses descripteurs de fichiers pour trouver dans quoi il est canalisé.
$ 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
De plus, si vous êtes chanceux, les différentes commandes du pipeline recevront des PID consécutifs, ce qui le rendra un peu plus facile.
Je n'ai pas de script pour le faire, mais j'ai prouvé le concept.
Une autre façon pourrait être d'accéder à la $BASH_COMMANDvariable automatique, mais elle est intrinsèquement volatile et difficile à saisir la valeur souhaitée.
Je pense que vous ne pouvez l'attraper que via un eval, ce qui implique également d'invoquer vos lignes de commande d'une manière spéciale, comme dans:
Ici, il $BASH_COMMANDest développé tout en le purgeant jusqu'au evalbit de chaîne, et la chaîne résultante est ainsi "instantanée" dans une $CMDvariable d' aide .
Merci pour vos réponses. J'ai testé différentes choses et suis arrivé au script de test suivant:
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
Tests:
$ ./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.
L'historique de la ligne de commande fonctionne uniquement sans Shebang sur la ligne supérieure du script. Je ne sais pas si cela fonctionnera de manière fiable et sur d'autres systèmes également.
Je n'ai pas pu supprimer la sortie de "readlink" (ou "file" comme suggéré par Archemar), lorsque le statut a réussi ("/ dev / pts / 3"). La sortie de la tuyauterie vers / dev / null ou vers une variable entraînerait un dysfonctionnement. Donc, ce ne serait pas une option pour moi dans un script.
La vérification ATS mentionnée par muru est facile et peut-être déjà suffisante pour certains cas d'utilisation.
Edit: Mon crédit va à mosvy, car la question était de savoir comment obtenir la ligne de commande complète et pas seulement pour déterminer si le script est sur un canal. J'aime la partie simple "fc -nl -0" dans sa réponse, car aucune configuration système supplémentaire n'est nécessaire. Ce n'est pas une solution à 100%, mais c'est juste pour mon usage personnel et donc suffisant. Merci à tous les autres pour votre aide.
Le contrôle ATS peut également être fait pour stdin: [ -t 0 ]. Vous pouvez donc vérifier si stdin ou stdout n'est pas un ATS et procéder en conséquence.
muru
Si vous voulez savoir si la sortie standard est un canal, vous pouvez utiliser sur Linux if [ -p /dev/stdout ]; ...(tout comme readlink /proc/self/fd/..cela ne fonctionne pas sur BSD).
mosvy
2
Le script doit fonctionner IMNSHO. le echo -ene veut certainement pas le -e. Vous avez besoin de plus de cas de test, de redirection vers un fichier, d'être invoqué à l'intérieur $(...). Cependant, je vous exhorte à considérer si c'est une bonne idée. Des programmes comme ceux lsqui modifient leur sortie selon qu'ils sortent vers un tty ou un pipe sont ennuyeux à utiliser.
[ -t 1 ]
unix.stackexchange.com/a/401938/70524Réponses:
Il n'y a aucun moyen de le faire en général .
Mais un
bash
shell interactif peut tirer parti du mécanisme d'historique et duDEBUG
piège pour "dire" aux commandes qu'il exécute la ligne de commande complète à laquelle ils appartiennent via une variable d'environnement:la source
non
bash (ou votre shell) va bifurquer deux commandes distinctes.
test.sh arg1
grep "xyz"
test.sh
ne pouvait pas savoir à propos de grep.vous pourriez cependant savoir que vous êtes "à l'intérieur" d'un tuyau en testant
/proc/self/fd/1
test.sh
qui fonctionnent comme
(Modifier) voir le commentaire de muru sur le fait de savoir si vous êtes sur une pipe.
la source
En utilisant
/proc/self/fd
, vous pouvez voir si vous êtes dans un pipeline ainsi qu'un ID pour le tuyau. Si vous parcourez la/proc/\*/fd
recherche du tuyau correspondant, vous pouvez trouver le PID de l'autre extrémité du tuyau. Avec le PID, vous pouvez ensuite lire/proc/$PID/cmdline
et répéter le processus sur ses descripteurs de fichiers pour trouver dans quoi il est canalisé.De plus, si vous êtes chanceux, les différentes commandes du pipeline recevront des PID consécutifs, ce qui le rendra un peu plus facile.
Je n'ai pas de script pour le faire, mais j'ai prouvé le concept.
la source
Une autre façon pourrait être d'accéder à la
$BASH_COMMAND
variable automatique, mais elle est intrinsèquement volatile et difficile à saisir la valeur souhaitée.Je pense que vous ne pouvez l'attraper que via un
eval
, ce qui implique également d'invoquer vos lignes de commande d'une manière spéciale, comme dans:Ici, il
$BASH_COMMAND
est développé tout en le purgeant jusqu'aueval
bit de chaîne, et la chaîne résultante est ainsi "instantanée" dans une$CMD
variable d' aide .Petit exemple:
Naturellement, cela peut aussi fonctionner (en fait mieux) tout en invoquant des scripts par exemple
sh -c
oubash -c
, comme dans:Ici sans purger la variable.
la source
Merci pour vos réponses. J'ai testé différentes choses et suis arrivé au script de test suivant:
test.sh:
Tests:
L'historique de la ligne de commande fonctionne uniquement sans Shebang sur la ligne supérieure du script. Je ne sais pas si cela fonctionnera de manière fiable et sur d'autres systèmes également.
Je n'ai pas pu supprimer la sortie de "readlink" (ou "file" comme suggéré par Archemar), lorsque le statut a réussi ("/ dev / pts / 3"). La sortie de la tuyauterie vers / dev / null ou vers une variable entraînerait un dysfonctionnement. Donc, ce ne serait pas une option pour moi dans un script.
La vérification ATS mentionnée par muru est facile et peut-être déjà suffisante pour certains cas d'utilisation.
Edit: Mon crédit va à mosvy, car la question était de savoir comment obtenir la ligne de commande complète et pas seulement pour déterminer si le script est sur un canal. J'aime la partie simple "fc -nl -0" dans sa réponse, car aucune configuration système supplémentaire n'est nécessaire. Ce n'est pas une solution à 100%, mais c'est juste pour mon usage personnel et donc suffisant. Merci à tous les autres pour votre aide.
la source
[ -t 0 ]
. Vous pouvez donc vérifier si stdin ou stdout n'est pas un ATS et procéder en conséquence.if [ -p /dev/stdout ]; ...
(tout commereadlink /proc/self/fd/..
cela ne fonctionne pas sur BSD).echo -e
ne veut certainement pas le-e
. Vous avez besoin de plus de cas de test, de redirection vers un fichier, d'être invoqué à l'intérieur$(...)
. Cependant, je vous exhorte à considérer si c'est une bonne idée. Des programmes comme ceuxls
qui modifient leur sortie selon qu'ils sortent vers un tty ou un pipe sont ennuyeux à utiliser.