Nautilus: Visited directory via symlink, now I can't go one level up in the target directory hierarchy

Why this is a challenging question

The question has a few challenges:

  • nautilus does not communicate directly from the command line, to get the currently active directory for example, nor can you "send" the currently opened folder (-window) to another directory from the command line.
  • In the current path, as requested via "NAUTILUS_SCRIPT_CURRENT_URI", Nautilus does not return the real path to the current folder, but "sees" the link as if it was an actual folder.

The solution therefore is as dirty as it gets; we need to find workarounds. Below four options to solve the issue.

1. right- click to go one level up

To get the real path to the current directory, we have to retrieve information from the link. We can do that either by using ls -l on the link, which will output e.g.:

lrwxrwxrwx 1 jacob jacob 35 jan 15 08:23 /home/jacob/Bureaublad/Flyer_st/Verwijzing naar Site_current -> /home/jacob/Bureaublad/Site_current

where the section after -> is the real path inside the symlink, or, using python:

real = os.path.realpath("/path")

Using this in a nautilus script, we can indirectly get the real path to the current file or folder.

Then if we have the path, how do we make nautilus move one level up?

Again, we cannot solve this and keep our hands clean. To move one level up, we first edit the found path a bit, from:

/path/to/a/folder

into

/path/to/a

then, using xdotool to simulate Ctrl+L (the GUI shortcut to insert a path into a nautilus window, since there is no cli option to move to another directory using the current window), and subsequently make xclip paste the edited path + Enter, we have a working solution!

In practice

  1. We are in a folder, opened from a link ("Link to Telegram") on my Desktop. The real folder is a sub folder of my Downloads folder:

    enter image description here

  2. Then if we right- click on any of the files inside the folder to run the script:

    enter image description here

  3. Automatically, the path to the superior directory is inserted:

    enter image description here

  4. And, also automatically, Return is pressed, and we move one directory level up:

    enter image description here

The script

#!/usr/bin/env python3
import subprocess
import os
import time

def run(cmd):
    subprocess.call(["/bin/bash", "-c", cmd])

current = os.getenv("NAUTILUS_SCRIPT_CURRENT_URI").replace("file://", "").replace("%20", " ")
real = os.path.realpath(current)
up = os.path.abspath(os.path.join(real, os.pardir))
run("xdotool key Control_L+l")
run("printf '"+up+"' | xclip -selection clipboard")
run("xdotool key Control_L+v")
# confirm by virtually press Return
time.sleep(0.1)
run("xdotool key Return")

How to set up

  1. The script needs both xdotool and xclip:

    sudo apt-get install xdotool xclip
    
  2. create, if it doesn't exist already, the directory

    ~/.local/share/nautilus/scripts
    
  3. Copy the script above into an empty file, save it as level_up (no extension) in ~/.local/share/nautilus/scripts, and make it executable

  4. You might have to log out and back in.
  5. Now you should be able to run the script by right- click on a file (any) > scripts > level_up:

    enter image description here


[EDIT] I changed the script above to paste the path into the nautilus window, instead of making xdotool type it. It needs xclip to be installed, but it is a major improvement, especially on very long paths.


2. Alternatively, open a new nautilus window in the superior directory

You could avoid using xdotool, by making the script open a new nautilus window, in the parent's directory. The script would then be even shorter:

#!/usr/bin/env python3
import subprocess
import os

def run(cmd):
    subprocess.call(cmd)

current = os.getenv("NAUTILUS_SCRIPT_CURRENT_URI").replace("file://", "").replace("%20", " ")
real = os.path.realpath(current)
up = real[:real.rfind("/")]
subprocess.Popen(["nautilus", up])

In this case, you wouldn't need to install xdotool. We could even extend the script by closing the original window and placing the new window exactly in the same position (& size).

The downside is that the history of the original window is lost this way.

3. An additional solution: alternative way to (automatically) create links

Not relevant to existing links, but when used from the GUI, a nautilus script to automatically create executable .desktop files on right-click might be helpful:

right-click on the directory to create a shortcut (behaving as a link)

enter image description here

Unlike symlinks, these links will take you to the actual folder, without behaving as a folder itself:

enter image description here

The script

#!/usr/bin/env python3
import subprocess
import os

current = os.getenv(
    "NAUTILUS_SCRIPT_SELECTED_FILE_PATHS"
    ).replace("file://", "").replace("%20", " ").strip()

if os.path.isdir(current):
    parent = os.path.abspath(os.path.join(current, os.pardir))
    fldr_path = '"'+current+'"'
    folder = current[current.rfind("/")+1:]
    linkfilename = parent+"/"+folder+"link.desktop"
    linkdata = [
        "[Desktop Entry]",
        "Type=Application",
        "Name=Link to -> "+folder,
        "Icon=folder",
        "Exec=nautilus "+fldr_path,
        ]
    with open(linkfilename, "wt") as wt:
        for l in linkdata:
            wt.write(l+"\n")
    command = "chmod +x "+"'"+linkfilename+"'" 
    subprocess.Popen(["/bin/bash", "-c", command])

How to use

  1. Copy the script into an empty file, save it as make_link (no extension) in ~/.local/share/nautilus/scripts, and make it executable
  2. Use the script by choosing it as a right- click option as in the first image. An executable .desktop file will be created in the same directory, move it elsewhere if you need to; the linked path is absolute.

Give the link an distinguishing icon

You could give the alternative link a distinguishing icon. If you search inside the directory /usr/share/icons for "folder", numerous valid options pop up.

If in the script the line "Icon=folder", is replaced by Icon=stock_folder-copy, (use the icon name without extension), the result on my system is:

enter image description here

Of course you can use your own custom icon as well, but if you use full paths (don't use ~), you should include the icon's extension.

4. Move to the superior directory with a short cut key

Probably the most convenient option; with the nautilus window in front, press a short cut key to move one directory up.

The script

#!/usr/bin/env python3
import subprocess
import time
import os

def get(cmd):
    return subprocess.check_output(cmd).decode("utf-8").strip()

def run(cmd):
    subprocess.call(["/bin/bash", "-c", cmd])

# get information on the active window
front = get(["xprop", "-id", get(["xdotool", "getactivewindow"])])
# (only) if it is a "normal" nautilus window, take action
if 'WM_CLASS(STRING) = "nautilus", "Nautilus"' in front:
    # "virtually" press Ctrl + l
    run("xdotool key Control_L+l"); time.sleep(0.05)
    # copy the current path, calculate the "real" parent directory
    real = os.path.realpath(get(["xclip", "-o"]))
    up = os.path.abspath(os.path.join(real, os.pardir))
    time.sleep(0.1)
    # enter the superior directory
    run("printf '"+up+"' | xclip -selection clipboard")
    run("xdotool key Control_L+v")
    # confirm by virtually press Return
    time.sleep(0.1)
    run("xdotool key Return")

To use

  1. For this solution, both xclip and xdotool Need to be on your system.

    sudo apt-get install xdodool xclip
    
  2. Copy the script into an empty file, save it as level_up.py (anywhere).

  3. Add it to a shortcut key: choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command:

    python3 /path/to/level_up.py
    

NB The shortcut options are a bit limited in this case, since the script itself will simulate Ctrl+L, and Ctrl+Alt+L will make you log out... Ctrl+\ worked fine on my system.

Explanation

This script also simulates Ctrl+L, but instead of using nautilus' "NAUTILUS_SCRIPT_CURRENT_URI", it uses xclip to copy the automatically selected path in the nautilus window. Like option 1, the script then calculates the real path and derives the superior directory.

This option might be useful if you prefer the keyboard to using right- click.


Or for Ubuntu 14.04, nautilus 3.10-1, with the xdotool package added, just use the following in your .local/share/nautilus/scripts/updirtree file:

# In nautilus, the pwd is the actual, not the link path
xdotool key ctrl-l
xdotool type "$(dirname $(pwd))" "
"

The final quote should just contain a newline or return (0x0a). The pwd from within nautilus produces a different result than when run from a bash/terminal -- it returns the actual path, not the path using the link.


I agree it makes no sense, it's undocumented, and I can't even figure out what sort of execution environment is running the code (I can't find any shell which produces that result), but it works. It's a hack, which is why I included the version of nautilus. Who knows how long it will work? Might break at the next nautilus upgrade (or the unknown interpreter), but for me, it works on links to mounted locations, links to places in the directory tree, or just plain locations in the directory tree.