Wie kann ich feststellen, bei welchem ​​Prozess eine Datei unter Linux geöffnet ist?

124

Ich möchte feststellen, welcher Prozess Eigentümer einer Sperrdatei ist. Die Sperrdateien sind einfach eine Datei mit einem bestimmten Namen, der erstellt wurde.

Wie kann ich feststellen, bei welchem ​​Prozess eine bestimmte Datei unter Linux geöffnet ist? Vorzugsweise wäre ein Einzeilentyp oder eine bestimmte Linux-Tool-Lösung optimal.

Danny
quelle

Antworten:

55

Sie können dafür auch verwenden fuser:

~> less .vimrc
# put in background
~> fuser .vimrc
.vimrc:              28135
~> ps 28135
  PID TTY      STAT   TIME COMMAND
28135 pts/36   T      0:00 less .vimrc
Nathan Fellman
quelle
Das war großartig, aber um es in einem Skript zu verwenden, musste ich die Ausgabelänge überprüfen.
Chovy
Was meinst du mit der Ausgabelänge?
Nathan Fellman
if [ Fixiereinheit "$ file" `]; dann exit`
chovy 21.08.13
1
Die Fixiereinheit hat ein seltsames Verhalten bei den Exit-Codes. Es gibt 1 Exitcode mit zwei Zuständen zurück: Ein / ein interner Fehler, geprüfte Datei nicht gefunden usw., B / kein Prozess hat die angegebene Datei geöffnet. In der Situation A / wird eine Fehlermeldung an den Ausgang ausgegeben. Leider wird, wenn die Datei verfügbar und von etwas geöffnet ist, eine Ausgabe mit dem Beendigungscode 0 generiert. Es ist besser, wenn die Fixiereinheit mit drei Codes beendet wird, nicht mit zwei wie derzeit. lsoft ist eine etwas schlechtere Lösung, da dies langsamer funktioniert.
Znik
Dies ist im Wesentlichen dasselbe Muster wie das lsfolgende: Es gibt den Exit-Code 2 zurück, wenn ein Fehler vorliegt (z. B. ungültige Option angegeben) oder die Datei nicht gefunden wurde (und 0, wenn Informationen erfolgreich gemeldet wurden).
Scott
144

Auf den meisten Linux-Systemen lsof NAMEerledigt die Arbeit:

fin@r2d2:~$ lsof /home/fin
COMMAND   PID USER   FD   TYPE DEVICE SIZE    NODE NAME
bash    21310  fin  cwd    DIR    8,1 4096 5054467 /home/fin
lsof    21320  fin  cwd    DIR    8,1 4096 5054467 /home/fin
lsof    21321  fin  cwd    DIR    8,1 4096 5054467 /home/fin
fin@r2d2:~$
Flosse
quelle
4
Und was ist, wenn Sie nicht genug haben?
JoseLSegura
3
@JoseLSegura: Ich nehme an, Sie sind einfallsreich genug, um die Antwort 'dann installiere lsof' für Sie nutzlos zu machen. Können Sie Ihr Problem näher erläutern? Wenn Sie nicht über root verfügen, müssen Sie wahrscheinlich nicht herausfinden, ob die Datei von einem anderen Benutzer geöffnet wurde.
Michael Scheper
Dies scheint nicht für Dateien zu funktionieren, nur für Verzeichnisse
Jason
@Jason: Es funktioniert für Dateien, aber cwdZeilen (die als aktuelles Arbeitsverzeichnis eines Prozesses verwendet werden) melden nur Verzeichnisse.
Reinierpost
9

Das Öffnen einer Datei ist keine Sperre, denn wenn jeder Prozess zuerst überprüfen muss, ob die Datei geöffnet ist, und nicht fortfahren muss, wenn dies der Fall ist, oder sie erstellen / öffnen, wenn dies nicht der Fall ist, können durchaus zwei Prozesse gleichzeitig prüfen, ob beide dies gefunden haben dass es nicht geöffnet ist, dann erstellen oder öffnen beide es.

Um eine Datei als Sperre zu verwenden, muss der Prüf- und Sperrvorgang eine einzige unterbrechungsfreie Operation sein. Sie können dies in einem Unix-Dateisystem erreichen, indem Sie eine Datei im schreibgeschützten Modus erstellen und zum Entsperren entfernen. Wenn die Datei vorhanden ist (und schreibgeschützt ist), schlägt die Dateierstellung fehl, sodass Sie die Prüfung und Sperre in einer einzelnen atomaren Operation erhalten.

Wenn es sich bei Ihrem Sperrprozess um ein Shell-Skript handelt, das als Dämon ausgeführt wird, können Sie diesen Effekt erzielen, indem Sie umaskeine Einstellung pro Prozess verwenden, mit der die Berechtigungen festgelegt werden, mit denen neue Dateien erstellt werden:

oldumask = $ (umask)
umask 222 # Dateien erstellen, die auch für den Eigentümer nicht schreibbar sind
if echo $$> / var / lock / foo
dann
    : Sperrung erfolgreich
sonst
    : Sperren fehlgeschlagen
fi
umask $ oldumask
Dadurch wird auch die PID des Besitzers in die Datei geschrieben, wodurch das andere Problem behoben wird: cat /var/lock/foo
In Bezug auf die spezifische Frage "Welche Prozesse haben diese Datei geöffnet?" Kann dies hilfreich sein, wenn Sie ein Dateisystem aushängen möchten, dies jedoch nicht können, da in einem Prozess eine Datei geöffnet ist. Wenn Sie diese Befehle nicht zur Verfügung haben, können Sie /procals root fragen :

ls -l /proc/*/cwd | grep '/var/lock/foo$'

oder als sterblicher Benutzer:

ls -l /proc/*/cwd 2>/dev/null | grep '/var/lock/foo$'

Martinwguy
quelle
Die Methode `ls -l 'funktioniert unter Linux, scheint jedoch nicht für CygWin zu funktionieren: Es gibt keine Informationen zum Sperren von Dateien. Würdest du nicht wissen, wie man löst? Vielen Dank.
Sopalajo de Arrierez
Nein, Sie erstellen keine schreibgeschützte Datei für eine Sperre, da die Datei bei einem Absturz Ihrer App immer noch vorhanden ist. Es ist mental, den Benutzer zu zwingen, den Mist zu beseitigen, nachdem die App abgestürzt ist.
polkovnikov.ph
6

Wenn Sie wissen möchten, welcher Dateideskriptor des exakten Prozesses auf Ihre Datei verweist, ohne lsofoder fuser- suchen Sie durch /proc:

$ find /proc -regex '\/proc\/[0-9]+\/fd\/.*' -type l -lname "*$1*" -printf "%p -> %l\n" 2> /dev/null

Ersetzen Sie $1durch den geöffneten Dateinamen, nach dem Sie suchen. Sie können das -printffür alles ändern, was Sie sehen möchten, oder es egrep -o '[0-9]+' | head -1zur Verwendung mit den Informationen für diesen Prozess weiterleiten.ps -Fp <pid>

Die Antwort von @fin ist natürlich die beste Antwort. Um jedoch auf den Kommentar von @ JoseLSegura zu antworten , war die obige Lösung meine Antwort.$ lsof <filename>

Scott
quelle
2

Ich fand heraus, dass die Verwendung der akzeptierten Antwort nicht die Prozesse auflistete, die mein Verzeichnis verwendeten (Ubuntu 14.04).

Am Ende habe ich lsof (list open files) verwendet und die Ausgabe überprüft, um den fehlerhaften Prozess zu finden:

lsof | egrep "<regexp-for-your-file>"
Eosis
quelle
Eine sauberere und schnellere Methode für diese Verwendung lsofist die Option -R. zB: lsof -R [filename]
tron5