3

If I do a w, I can see that a user is editing a certain file in vi.

However there are several files with the same name in different directories.

How do I see which of these files is the one that the user is editing?

2

6 Answers 6

9

You can use lsof selecting the user and searching for the vim process as in:

sudo lsof -u user -a -c vim | grep swp

As @Fox point outs, the classical vi creates a temp file on /var/tmp so the alternative to see it, should be (not tested).

sudo lsof -u user -a -c vi | grep '/var/tmp/'

However, as @Fox points out, you won't be able to correlate it with the classical vi to the actual file, and then you would need the tools I talk about next on the answer (for classical vi, for vim it would suffice the lsof); usually nowadays in Linux you are using vim when invoking vi.

See 15 Linux lsof Command Examples (Identify Open Files)

Returning to the vim example, we will see then the swap file being used named after file is opened as in .file.swp

If user user1 is doing vi file:

$ sudo lsof -c vi -a -u user1 | grep swp
vi      3615  user1  3u   REG    8,1    12288 265061 /home/user1/.file.swp

From man lsof

-a causes list selection options to be ANDed

-cc This option selects the listing of files for processes executing the command that begins with the characters of c. Multiple commands may be specified, using multiple -c options. They are joined in a single ORed set before participating in AND option selection.

-u s This option selects the listing of files for the user whose login names or user ID numbers are in the comma-separated set s

Aside from lsof, you can also use as root, sysdig, which is a powerful debugging framework:

This will show all files open in the system in real time, listing user,pid and process as soon as they are opened:

sudo sysdig -p "%12user.name %6proc.pid %12proc.name %3fd.num %fd.typechar %fd.name" evt.type=open"

sysdig: system-level exploration and troubleshooting tool

Sysdig instruments your physical and virtual machines at the OS level by installing into the Linux kernel and capturing system calls and other OS events. Then, using sysdig's command line interface, you can filter and decode these events in order to extract useful information and statistics.

Sysdig can be used to inspect live systems in real-time, or to generate trace files that can be analyzed at a later stage.

As other useful tool for sysadmins, you can also install snoopy, which logs all invocations of processes called to syslog. If the user invokes in the command line vi file, you will see it in the system logs.

Beware that after snoopy is installed, it will be logging all the process invocations via execve() until you uninstall it (which you might want or not want to be happening all the time).

snoopy: execve() wrapper and logger

snoopy is merely a shared library that is used as a wrapper to the execve() function provided by libc as to log every call to syslog (authpriv). system administrators may find snoopy useful in tasks such as light/heavy system monitoring, tracking other administrator's actions as well as getting a good 'feel' of what's going on in the system (for example Apache running cgi scripts).

To install snoopy and sysdig:

$sudo apt-get install snoopy sysdig

See also the related question: Understanding what a Linux binary is doing

1
  • lsof will also require root if you are trying to see files opened by another user.
    – rrauenza
    Feb 8, 2018 at 22:53
2

This might work for some cases. You can us ps to find the process id of the vi instance editing the file:

$ w
...
username  pts/2    :0.0             11:42    2:34m  0.28s  0.27s vim foo

$ ps aux | grep 'vim foo'
...
username  55899 .... vim foo

Then, as root, look at the open file descriptors associated with that pid:

# ls -l /proc/55899/fd
...
lrwx------ 1 username group 64 Feb  8 14:23 6 -> /path/to/.foo.swp

Given that, then you might be able to conclude that the file is /path/to/foo.

4
  • 2
    The lsof answers are better choices; that tool provides an abstraction over my answer. Feb 8, 2018 at 19:45
  • A test on my system, after vi file1 then :e file2, w outputs, among other things, fox … vi file1. ps waux | grep '[v]i file1' yields PID 14267. ls -l /proc/14267/fd yields 0 -> /dev/pts/24 (same for 1 and 2) and 3 -> /var/tmp/Ex0000014267. This is, of course, neither file1 nor file2
    – Fox
    Feb 8, 2018 at 19:48
  • 2
    "This might work for some cases" + "The `lsof answers are better". Yes, there are cases where my approach won't work. Feb 8, 2018 at 19:55
  • I've left almost the same comment on the other answers as well. The lsof command fails in exactly the same way — not to mention that in the lsof-based answers, using grep will match far more than just the command column, thus generating far too much output
    – Fox
    Feb 8, 2018 at 19:58
2

You need to use lsof:

$ lsof  |grep -i vim
2
  • A test on my system, after vi file1 then :e file2, lsof | grep -i '\bvi\b' outputs some shared libraries, /dev/pts/24 a few times, and /var/tmp/Ex0000014267, which is of course neither file1 nor file2
    – Fox
    Feb 8, 2018 at 19:55
  • 1
    Most editors read the file into a memory buffer or temp file, then close the original file. So you would have to run lsof at the moment that the user is reading or writing the file in order to catch it when the file is open.
    – Barmar
    Feb 8, 2018 at 22:46
1

do you want to see that from inside vi or from the shell ? -from vim

<ESC>:ls list buffers opened 

I think vi cannot but you can use ctrl+ww to swith between files

-from shell

lsof | grep -i  vi 
1
  • you have to filter lsof output of course :) to feet your needs see the answer of Rui F Ribeiro who give you a full example of it
    – francois P
    Feb 8, 2018 at 19:59
0

I'm assuming that you know what command the user ran, but that you want to know which directory they ran it from (so that if they ran vi myfile.txt, you know whether that's /home/user/myfile.txt, or /tmp/myfile.txt, or something else).

In that case, assuming you're running as root, you can do:

readlink /proc/<pid>/cwd

where <pid> is the process ID of the vi/vim process you're interested in - that will tell you the current directory of that process, which has a good chance of being the one you want.

Note, however, that:

  • The user can change the process's current directory after starting the editor (e.g. using the :cd command). You may also wish to check the current directory of the shell process that spawned the editor, though that's not 100% reliable either.
  • The user can open other files, and that won't show up in the command line - so they may be editing something else entirely.
0

If you don't have root but do have permissions to read the directories, your best bet is probably to look for the .swp files for the file in question (assuming the user hasn't changed vim's default swap location!):

$ find . -type f
./1/foo
./0/foo
./2/foo

$ cd 1
$ vi foo
^Z 
[1] 19650

$ cd ..
$ find -type f
./1/foo
./1/.foo.swp
./0/foo
./2/foo

Note, however, if you edit foo and .foo in the same directory, vim will need to make different temporary filename extensions:

-rw-r--r--   1 user grp  12288 Feb  8 14:59 .foo.swo
-rw-------   1 user grp   4096 Feb  8 14:58 .foo.swp

So you may wish to look using find . -user username -name '.*.sw*'

This feels a bit like an XY problem -- what larger problem are you trying to solve? If you're trying to manage multiple users editing common files, you may wish to move to a source management system.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .