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?
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityIf 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?
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
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
.
lsof
answers are better choices; that tool provides an abstraction over my answer.
Feb 8, 2018 at 19:45
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
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
You need to use lsof
:
$ lsof |grep -i vim
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
lsof
at the moment that the user is reading or writing the file in order to catch it when the file is open.
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
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:
: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.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.