How can I programmatically determine which files are currently open in evince?

TLDR:

for ip in $(pgrep -x evince); do lsof -F +p $ip|grep -i '^n.*\.pdf$'|sed s/^n//g; done

Explanation:

Document Viewer is the friendly name for the program /usr/bin/evince. So first we need to find the process ID (PID) of evince:

$ pgrep -x evince
22291

To list all files opened by this PID we will use the lsof command (note that we'll need to repeat this for every PID in case we have more than one instance of evince running)

$ lsof -F +p 22291
some other files opened
.
.
.
n/home/c0rp/File.pdf

Next we'll grep only for pdfs and discard the irrelevant n at start of line:

$ lsof -Fn +p 22291 | grep -i '^n.*\.pdf$' | sed s/^n//g
/home/c0rp/File.pdf

Finally to combine everything in one bash line:

for ip in $(pgrep -x evince); do lsof -F +p $ip|grep -i '^n.*\.pdf$'|sed s/^n//g; done

This one-liner was inspired from the answer of terdon which is also very interesting in the way it solves the same problem.


If you are interested in what n in lsof -Fn is for, here is quote from man lsof about the -F option:

OUTPUT FOR OTHER PROGRAMS
       When the -F option is specified, lsof produces output that is  suitable
       for  processing by another program - e.g, an awk or Perl script, or a C
       program. 
...
...
       These  are  the  fields  that  lsof will produce.  The single character
       listed first is the field identifier.
...
...
            n    file name, comment, Internet address
...
...

so -Fn, is saying show me file name, comment, Internet address


Another approach would be something like

$ for ip in $(pgrep -x evince); do lsof -F +p $ip  | grep -oP '^n\K.*\.pdf$'; done
/home/terdon/file1.pdf
/home/terdon/file2.pdf

Explanation

In general, whenever you want to search fro a process, pgrep is better than ps -ef | grep process since the latter will also match the grep process itself. For example:

$ ps -ef | grep emacs
terdon    6647  6424 23 16:26 pts/14   00:00:02 emacs
terdon    6813  6424  0 16:26 pts/14   00:00:00 grep --color emacs
$ pgrep emacs
6647

The -x option returns only processes whose entire name matches the string passed. This is needed because evince also starts a daemon (evinced) and that will also be matched without the -x (the -l is to print the name as well as the PID):

$ pgrep -l evince
4606 evince
4611 evinced
4613 evince
$ pgrep -lx evince
4606 evince
4613 evince

So, the for loop will run lsof on each of the PIDs returned by pgrep. These are then passed through grep. The -o option means "print only the matched portion of the line" and the -P activates Perl Compatible Regular Expressions which lets us use \K. In PCREs, \K means "discard everything matched before the \K ". In other words, since I am using-o, it will match lines beginning withnand ending with.pdfbut it will not print the matchedn`. The result is that only the file's name is printed.