`/ proc / $ PID / cwd`: Gibt es ein POSIX-Äquivalent?

8

Linux hat ein /procVerzeichnis und ein Dateisystem, die, soweit ich das beurteilen kann, nicht Teil von POSIX sind. In jedem /proc/$PIDUnterverzeichnis befindet sich ein symbolischer Link, cwdder auf das tatsächliche Arbeitsverzeichnis des Prozesses dieser PID verweist (der cwdLink ist immer aktuell).

Diese symbolische Verknüpfung ist für einige Anwendungsfälle praktisch, z. B. das Arbeiten mit unterschiedlichen Shells und das Austauschen von Dateien zwischen den beiden Shells (formal deren Arbeitsverzeichnisse).

Gibt es eine einfache Möglichkeit, etwas Ähnliches zu erhalten, nur mit der POSIX-Funktion?

Mehr zur Frage

Nach einem Kommentar, mehr Präzision: Es muss nicht unbedingt ein Link und eine Umgebungsvariable sein $<PID>_CWD, wäre auch so gut, obwohl ich auf den ersten Blick nicht glaube, dass es eine solche Lösung gibt. Es muss nur leicht zu referenzieren sein (z. B. symbolischer Link oder Umgebungsvariable) und jedes Mal auf dem neuesten Stand sein, wenn der andere Prozess das Arbeitsverzeichnis wechselt.

Die Lösung muss nicht unbedingt POSIX sein, und der wichtigste Aspekt ist die Portabilität, aber POSIX ist sicherlich eine Garantie.

Hibou57
quelle
1
Möchten Sie POSIX oder tragbar? Dinge können portabel sein, ohne in POSIX definiert zu sein.
Patrick
1
Ich glaube nicht, dass sich POSIX mit dieser Detailgenauigkeit und der Enge eines Anwendungsfalls befassen würde. Solaris und AIX verfügen beide über einen pwdxBefehl. Sie können also einfach einen Alias ​​oder eine Funktion erstellen, die pwdxunter Linux aufgerufen wird und sich umgibt, readlinkwenn Sie nach etwas Tragbarem suchen.
Bratchley
1
Tatsächlich gibt es auf meinem RHEL5-System einen pwdxBefehl, der mitgeliefert wird , procpssodass dies möglicherweise Ihre Antwort ist.
Bratchley
1
@ JoelDavis Eigentlich hat fast jedes Linux und Solaris pwdx. Aber FreeBSD nicht.
Ende
2
Unterhaltsame Tatsache: Wird getcwd(3)verwendet, indem Sie stat(".")und anrufen readdir(".."), eine passende Inode-Nummer finden und den Vorgang nach oben wiederholen, bis er das Stammverzeichnis erreicht. Viel Glück dabei , dass im Rahmen eines anderen Verfahrens. (Ich nehme an, man könnte verwenden ptrace, um einen Anruf an getcwd...)
zwol

Antworten:

6

Ich habe eine Lösung, die verwendet lsof. Es ist standardmäßig nicht auf BSD installiert. Wenn jemand es auf BSD verwenden möchte, muss es installiert werden.

Erstellen Sie ein Shell-Skript:

#!/bin/sh
lsof -p $1 | grep cwd | awk '{print $9}'

Kopieren Sie es in ein Verzeichnis in Ihrem Pfad. Es gibt das Arbeitsverzeichnis der PID aus, das im ersten Argument, IE, angegeben ist

$ script 1987
/home/enedil
enedil
quelle
3
Übrigens auch diese kleine Variation : lsof -p $PID | awk '/cwd/{print $9}'.
Hibou57
@ Hibou57 ok, ich bin kein AWKExperte.
Ende
1
+1, ich wollte nicht, dass du auf 888 bleibst: p
Ramesh
2
Sie können ein wenig lsofOverhead mit nurlsof -d cwd -a -p $1
mr.spuratic
5

POSIX bietet nicht viel, um Informationen über nicht verwandte Prozesse zu erhalten. Es gibt pswirklich nur und es gibt keine Informationen über das aktuelle Verzeichnis. Die C-Level-APIs sind nicht besser (tatsächlich können die meisten Informationen, die von abgerufen werden, psnur durch Analysieren der Ausgabe abgerufen werden¹).

Lustigerweise bietet POSIX eine tragbare Möglichkeit, um umgekehrt zu sein: Wenn eine Datei angegeben ist, können Sie durch Aufrufen herausfinden, welche Prozesse sie geöffnet haben fuser. Das folgende Snippet listet die PIDs der Prozesse auf, die ein bestimmtes Arbeitsverzeichnis haben:

fuser -f "$directory_name" 2>&1 | sed -e '$!d' -e 's/.*://' -e 's/  */\
/' | sed -n 's/c$//p'

Wenn Sie Informationen zu Prozessen auf eine Weise erhalten möchten, die in der Praxis portabel ist, verwenden Sie lsof . Der Autor von lsof hat alle verschiedenen Methoden zum Abrufen von Informationen zu verschiedenen Unix-Varianten implementiert.

Für gelegentliches Surfen:

lsof -a -p "$pid" -d cwd

Für automatisiertes Parsen:

lsof -a -p "$pid" -d cwd -F n | sed -e '1d' -e '2s/^n//'

Beachten Sie, dass lsofZeilenumbrüche durch die Zeichenfolge ersetzt werden \n.

Einige Unix-Varianten bieten Methoden an, für die keine Software von Drittanbietern erforderlich ist. Diese Methoden sind jedoch zwangsläufig für jede Variante spezifisch. Ein sehr verwandter Hinweis finden Sie unter Portabilität von Dateideskriptor-Links

¹ Einige alte Unices haben pssetuid root und lesen den Kernelspeicher. Daher war die Verwendung dieser setuid-Binärdatei der einzige Weg, um diese Informationen zu erhalten.

Gilles 'SO - hör auf böse zu sein'
quelle
Ich bin mir nicht sicher, ob "es keine Informationen über das aktuelle Verzeichnis gibt": In den meisten Unixen können Sie ps auf zwei Arten verwenden: ps -options[= Unix-Optionen mit einem Bindestrich] oder ps options[= BSD-Stiloptionen ohne ein Strich]. Jeder kommt mit seinen eigenen Optionen ( -Xund Xsind wahrscheinlich nicht die gleiche Option). Mit BSD-Optionen kann man: ps auexwww |grep [f]oo |tr ' ' '\n' |grep 'CWD='das CWD von foo erhalten. Es funktioniert auf einem (Nicht-Gnu-Ps) Aix, auf einem (Gnu-Ps) Linux, aber es schlägt in Cygwin fehl :( Und auf Solaris müssen Sie abrechnen /usr/ucb/ps, um die richtigen Ps zu erhalten. Also wahrscheinlich Nicht-Posix?
Olivier Dulac
1
@OlivierDulac psist möglicherweise der klassische Unix-Befehl, der zwischen Unix-Varianten am stärksten voneinander abweicht . Es hat in letzter Zeit tendenziell konvergiert, aber POSIX standardisiert nur einige Optionen im SysV-Stil, und keine davon gibt das aktuelle Verzeichnis an. Ihr Befehl funktioniert nicht, meinten Sie PWD=eher als CWD=? Das gibt Ihnen nicht die CWD, sondern den Wert der PWDUmgebungsvariablen (oder eine falsche Übereinstimmung aufgrund der ungefähren Analyse), was normalerweise nur dann korrekt ist, wenn das Programm sein aktuelles Verzeichnis nach dem Start von a nicht geändert hat Schale.
Gilles 'SO - hör auf böse zu sein'
Sie haben absolut Recht, es ist das PWD zu erhalten (| grep 'PWD =') und zeigt nur an, wo der Befehl "von" gestartet wurde (dh was das PWD der Shell war, als der Befehl gestartet wurde). Dies ist manchmal nützlich (dh unter alten Aix hilft es, das aktuelle Skriptverzeichnis zu finden, wenn ps nur "./script" anzeigt und BASH_SOURCE [@] nicht verfügbar ist), gibt aber tatsächlich nicht die tatsächliche CWD von aus das Skript. Entschuldigung und danke für die Korrekturen. lsof scheint die tragbarste Wette für die Bedürfnisse der Frage zu sein. (Ich hatte bereits +1 Ihre Antwort, aber ich würde das jetzt verdoppeln, wenn ich könnte ^^)
Olivier Dulac
0

Ich werde meine eigene Antwort beisteuern.

Eine Option im Kontext einer interaktiven Shell (die Frage konzentriert sich auf diesen Kontext) könnte darin bestehen, automatisch einen Link à la zu pflegen /proc/$PID/cwd, indem die von Bash bereitgestellte Automatisierungsmöglichkeit verwendet wird:

PROMPT_COMMAND="ln -sfT \$(pwd) ~/$LINK_NAME"

Die fOption ist erforderlich, da der Link häufig überschrieben wird. Die TOption ist erforderlich, da die fOption ansonsten anscheinend ordnungsgemäß funktioniert.

Muscheln können kooperativ gemacht werden, indem dies in Beispiel verwendet wird ~/.bashrc:

if [ -v CWD_LINK_NAME ]; then
   PROMPT_COMMAND='ln -sfT "$(pwd)" "'$CWD_LINK_NAME'";'$PROMPT_COMMAND
   declare -r CWD_LINK_NAME
   function rm_cwd_link() {
      rm "$CWD_LINK_NAME"
   }
   trap rm_cwd_link EXIT
fi

Eine Shell oder ein Terminal kann mit CWD_LINK_NAMEeinem beliebigen relevanten Wert ausgeführt werden. Ex.CWD_LINK_NAME="~/$SOME_ROLE_NAME" gnome-terminal

Eine weitere Alternative ist das gleiche Konzept mit der Birne verfolgen in einem variablen Arbeitsverzeichnis, das Tracking auf beide basieren @Gilles und @enedil Beiträge:

PROMPT_COMMAND="PEAR_WD=\$(lsof -p $PID | awk '/cwd/{print \$9}')"

Dies ist jedoch weniger genau und weniger praktisch, obwohl es in den seltenen Fällen immer noch die einzige Möglichkeit ist, die $PROMPT_COMMANDnicht in der anderen Shell eingestellt werden kann.

Ich bin für die erste Option (ich warte immer noch, bevor ich eine Antwort auswähle, falls jemals andere Beiträge kommen).

Hibou57
quelle