Können Sie klarstellen, was Sie unter "Befehlszeile" verstehen?
Bart
Ich frage mich nur, ob es eine spezielle
Dollarvariable
2
Was wäre Ihr Anwendungsfall dafür?
Kusalananda
9
@hellcode Sie müssen nicht wissen, ob Sie dafür in einer Pipe sind. Überprüfen Sie einfach, ob die Ausgabe ein TTY ist. [ -t 1 ]unix.stackexchange.com/a/401938/70524
Es gibt im Allgemeinen keine Möglichkeit, dies zu tun .
Eine interaktive bashShell kann jedoch den Verlaufsmechanismus und die DEBUGFalle nutzen, um den Befehlen, über die sie ausgeführt wird, über eine Umgebungsvariable die vollständige Befehlszeile mitzuteilen, zu der sie gehört:
Dies ist zwar nützlich, funktioniert aber nur unter Linux - nicht unter anderen Unixen
Scott Earle
2
Mithilfe von /proc/self/fdkönnen Sie sehen, ob Sie sich in einer Pipeline befinden, sowie eine ID für die Pipe. Wenn Sie /proc/\*/fdnach dem passenden Rohr suchen, finden Sie die PID am anderen Ende des Rohrs. Mit der PID können Sie dann /proc/$PID/cmdlineden Vorgang in den Dateideskriptoren lesen und wiederholen, um herauszufinden, in was er geleitet wird.
$ 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
Wenn Sie Glück haben, erhalten die verschiedenen Befehle in der Pipeline aufeinanderfolgende PIDs, was die Arbeit etwas erleichtert.
Ich habe eigentlich kein Skript dafür, aber ich habe das Konzept bewiesen.
Ein anderer Weg könnte der Zugriff auf die $BASH_COMMANDautomatische Variable sein, aber es ist von Natur aus volatil und schwierig, den gewünschten Wert zu erfassen.
Ich denke, Sie konnten es nur über ein abfangen eval, was auch das Aufrufen Ihrer Befehlszeilen auf besondere Weise beinhaltet, wie in:
Hier $BASH_COMMANDwird es erweitert, während es gleichzeitig bis zum evalBit der Zeichenfolge gelöscht wird, und die Ergebniszeichenfolge wird somit in eine $CMDHilfsvariable "aufgenommen" .
Danke für deine Antworten. Ich habe verschiedene Dinge getestet und bin zu folgendem Testskript gekommen:
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.
Der Befehlszeilenverlauf funktioniert nur ohne Shebang in der obersten Zeile des Skripts. Ich weiß nicht, ob dies zuverlässig und auch auf anderen Systemen funktioniert.
Ich konnte die Ausgabe von "readlink" (oder "file", wie von Archemar vorgeschlagen) nicht unterdrücken, als der Status erfolgreich war ("/ dev / pts / 3"). Die Weiterleitung der Ausgabe an / dev / null oder an eine Variable würde zu Fehlfunktionen führen. Das wäre also keine Option für mich in einem Skript.
Der von muru erwähnte TTY-Check ist einfach und für einige Anwendungsfälle möglicherweise bereits ausreichend.
Bearbeiten: Mein Verdienst geht an mosvy, weil die Frage war, wie man die komplette Befehlszeile erhält und nicht nur, ob sich das Skript in einer Pipe befindet. Ich mag den einfachen Teil "fc -nl -0" in seiner Antwort, da keine weitere Systemkonfiguration erforderlich ist. Es ist keine 100-prozentige Lösung, aber dies ist nur für meinen persönlichen Gebrauch und daher ausreichend. Vielen Dank an alle anderen für Ihre Hilfe.
Die TTY-Prüfung kann auch für stdin durchgeführt werden : [ -t 0 ]. Sie können also überprüfen, ob stdin oder stdout kein TTY ist, und entsprechend vorgehen.
Muru
Wenn Sie wissen möchten, ob das stdout eine Pipe ist, können Sie es unter Linux verwenden if [ -p /dev/stdout ]; ...(genau wie readlink /proc/self/fd/..dies unter BSD nicht funktioniert).
Mosvy
2
Das Skript benötigt Arbeit IMNSHO. das echo -ewill das mit ziemlicher sicherheit nicht -e. Sie benötigen weitere Testfälle, die in eine Datei umgeleitet und darin aufgerufen werden $(...). Ich möchte Sie jedoch dringend bitten, zu prüfen, ob dies eine gute Idee ist. Programme wie solche, lsdie ihre Ausgabe ändern, je nachdem, ob sie an ein tty oder eine Pipe ausgegeben werden, sind ärgerlich zu verwenden.
[ -t 1 ]
unix.stackexchange.com/a/401938/70524Antworten:
Es gibt im Allgemeinen keine Möglichkeit, dies zu tun .
Eine interaktive
bash
Shell kann jedoch den Verlaufsmechanismus und dieDEBUG
Falle nutzen, um den Befehlen, über die sie ausgeführt wird, über eine Umgebungsvariable die vollständige Befehlszeile mitzuteilen, zu der sie gehört:quelle
Nein
bash (oder Ihre Shell) gibt zwei verschiedene Befehle aus.
test.sh arg1
grep "xyz"
test.sh
Ich konnte nicht wissen, wie ich grep folge.Sie könnten jedoch durch Testen wissen, dass Sie sich "in" einem Rohr befinden
/proc/self/fd/1
test.sh
welche laufen als
(Bearbeiten) Siehe Murus Kommentar darüber, ob Sie sich auf einer Pfeife befinden.
quelle
Mithilfe von
/proc/self/fd
können Sie sehen, ob Sie sich in einer Pipeline befinden, sowie eine ID für die Pipe. Wenn Sie/proc/\*/fd
nach dem passenden Rohr suchen, finden Sie die PID am anderen Ende des Rohrs. Mit der PID können Sie dann/proc/$PID/cmdline
den Vorgang in den Dateideskriptoren lesen und wiederholen, um herauszufinden, in was er geleitet wird.Wenn Sie Glück haben, erhalten die verschiedenen Befehle in der Pipeline aufeinanderfolgende PIDs, was die Arbeit etwas erleichtert.
Ich habe eigentlich kein Skript dafür, aber ich habe das Konzept bewiesen.
quelle
Ein anderer Weg könnte der Zugriff auf die
$BASH_COMMAND
automatische Variable sein, aber es ist von Natur aus volatil und schwierig, den gewünschten Wert zu erfassen.Ich denke, Sie konnten es nur über ein abfangen
eval
, was auch das Aufrufen Ihrer Befehlszeilen auf besondere Weise beinhaltet, wie in:Hier
$BASH_COMMAND
wird es erweitert, während es gleichzeitig bis zumeval
Bit der Zeichenfolge gelöscht wird, und die Ergebniszeichenfolge wird somit in eine$CMD
Hilfsvariable "aufgenommen" .Kleines Beispiel:
Natürlich kann es auch funktionieren (eigentlich besser) beim Aufrufen von Skripten durch zB
sh -c
oderbash -c
, wie in:Hier ohne die Variable zu löschen.
quelle
Danke für deine Antworten. Ich habe verschiedene Dinge getestet und bin zu folgendem Testskript gekommen:
test.sh:
Tests:
Der Befehlszeilenverlauf funktioniert nur ohne Shebang in der obersten Zeile des Skripts. Ich weiß nicht, ob dies zuverlässig und auch auf anderen Systemen funktioniert.
Ich konnte die Ausgabe von "readlink" (oder "file", wie von Archemar vorgeschlagen) nicht unterdrücken, als der Status erfolgreich war ("/ dev / pts / 3"). Die Weiterleitung der Ausgabe an / dev / null oder an eine Variable würde zu Fehlfunktionen führen. Das wäre also keine Option für mich in einem Skript.
Der von muru erwähnte TTY-Check ist einfach und für einige Anwendungsfälle möglicherweise bereits ausreichend.
Bearbeiten: Mein Verdienst geht an mosvy, weil die Frage war, wie man die komplette Befehlszeile erhält und nicht nur, ob sich das Skript in einer Pipe befindet. Ich mag den einfachen Teil "fc -nl -0" in seiner Antwort, da keine weitere Systemkonfiguration erforderlich ist. Es ist keine 100-prozentige Lösung, aber dies ist nur für meinen persönlichen Gebrauch und daher ausreichend. Vielen Dank an alle anderen für Ihre Hilfe.
quelle
[ -t 0 ]
. Sie können also überprüfen, ob stdin oder stdout kein TTY ist, und entsprechend vorgehen.if [ -p /dev/stdout ]; ...
(genau wiereadlink /proc/self/fd/..
dies unter BSD nicht funktioniert).echo -e
will das mit ziemlicher sicherheit nicht-e
. Sie benötigen weitere Testfälle, die in eine Datei umgeleitet und darin aufgerufen werden$(...)
. Ich möchte Sie jedoch dringend bitten, zu prüfen, ob dies eine gute Idee ist. Programme wie solche,ls
die ihre Ausgabe ändern, je nachdem, ob sie an ein tty oder eine Pipe ausgegeben werden, sind ärgerlich zu verwenden.