Как я могу определить, какой процесс имеет файл, открытый в Linux?

124

Я хотел бы определить, какой процесс владеет файлом блокировки. Файлы блокировки - это просто файл с определенным именем, которое было создано.

Итак, как я могу определить, какой процесс имеет определенный файл, открытый в Linux? Предпочтительно однострочник или конкретное инструментальное решение для Linux будет оптимальным.

Дэнни
источник

Ответы:

55

Вы также можете использовать 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
Натан Феллман
источник
это было здорово, но чтобы использовать его в скрипте, мне нужно было проверить длину вывода.
Чови
что вы имеете в виду длину вывода?
Натан Феллман
if [ fuser "$ file" `]; затем выход`
Чови
1
У fuser странное поведение с кодами выхода. он возвращает 1 код выхода с двумя состояниями: A / некоторая внутренняя ошибка, проверенный файл не найден и т. д., B / нет, процесс открыл указанный файл. В ситуации A / выводится сообщение об ошибке. К сожалению, когда файл доступен и открыт чем-то, вывод генерируется, но с кодом выхода 0. Было бы лучше, если fuser завершит работу с тремя кодами, а не двумя, как в настоящее время. Софт немного хуже, потому что работает медленнее.
Znik
По сути, это тот же шаблон, который lsследует ниже - он возвращает код выхода 2, если есть ошибка (например, указана неверная опция) или файл не найден (и 0, если он успешно сообщает информацию).
Скотт
144

На большинстве систем Linux lsof NAMEделает работу:

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:~$
плавник
источник
4
А что если у тебя нет lsof?
JoseLSegura
3
@JoseLSegura: я предполагаю, что вы достаточно изобретательны, чтобы ответ «затем установите lsof» был бесполезен для вас. Можете ли вы рассказать о своей проблеме? Если у вас нет root, скорее всего, у вас нет привилегий, чтобы выяснить, есть ли у какого-либо пользователя открытый файл.
Майкл Шепер
кажется, это не работает для файлов, только для директоров
Джейсон
@Jason: он работает для файлов, но cwdстроки (которые используют отчет как текущий рабочий каталог процесса) только каталоги отчетов.
reinierpost
9

Открытие файла не является блокировкой, потому что, если каждый процесс должен сначала проверить, открыт ли файл, а не продолжить, если он есть, или создать или открыть его, если это не так, то два процесса вполне могут проверить одновременно, оба найдут что он не открыт, то создайте или откройте его.

Чтобы использовать файл в качестве блокировки, операция проверки и блокировки должна быть единственной непрерывной операцией. Вы можете добиться этого в файловой системе Unix, создав файл в режиме только для чтения и удалив его, чтобы разблокировать. Если файл существует (и доступен только для чтения), создание файла завершится неудачно, поэтому вы получаете проверку и блокировку в одной атомарной операции.

Если ваш процесс блокировки представляет собой сценарий оболочки, который будет работать как демон, вы можете получить этот эффект, используя параметр umaskдля каждого процесса, который устанавливает разрешения для создания новых файлов:

oldumask = $ (Umask)
umask 222 # создавать файлы, которые не доступны для записи владельцу
if echo $$> / var / lock / foo
тогда
    : блокировка прошла успешно
еще
    : блокировка не удалась
фи
umask $ oldumask
Это также записывает PID собственного процесса в файл, что решает вашу другую проблему: cat /var/lock/foo
Что касается конкретного вопроса «В каких процессах этот файл открыт?», Это может быть полезно, если вы хотите размонтировать файловую систему, но не можете, потому что у какого-то процесса есть открытый файл. Если у вас нет этих команд, вы можете задать их /procкак root:

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

или, как смертный пользователь:

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

martinwguy
источник
метод `ls -l 'работает для Linux, но, похоже, не работает для CygWin: там нет информации о блокировке файлов. Разве вы не знаете, как решить? Благодарю.
Сопалахо де Арриерес
Нет, вы не создаете файл только для чтения для блокировки, потому что, когда ваше приложение будет аварийно завершено, файл все равно будет там. Принуждение пользователя к очистке от дерьма после сбоя приложения является психическим.
polkovnikov.ph
6

Если вы хотите знать, какой именно дескриптор файла процесса ссылается на ваш файл без lsofили fuser- выполните поиск через /proc:

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

Замените $1на открытое имя файла, которое вы ищете. Вы можете изменить то, -printfчто вы хотите видеть, или указать egrep -o '[0-9]+' | head -1для использования информацию этого процесса.ps -Fp <pid>

Ответ на @fin является лучшим ответом, очевидно, но ответить @ комментарий JoseLSegura в , если это не доступно, решение выше , был мой ответ.$ lsof <filename>

Скотт
источник
2

Я обнаружил, что при использовании принятого ответа не было перечислено процессов, которые использовали мой каталог (ubuntu 14.04).

В конце концов, я использовал lsof (список открытых файлов) и набрал его вывод, чтобы найти процесс, вызывающий ошибку:

lsof | egrep "<regexp-for-your-file>"
Eosis
источник
Более чистый и быстрый способ для этого использования lsof- его выбор -R. например: lsof -R [filename]
tron5