2015. január 25.

Nautilus scripting in bash: processing multiple files / handle space in filenames

Where do I put the scripts? 

Nautilus scripts folder is in your user home directory:
in Ubuntu 12.04 and before: .gnome2/nautilus-scripts/
from Ubuntu 14.04: .local/share/nautilus/scripts/

You'll have to make all script files executable in order to be able to run them.
chmod +x

What does a nautilus script do? 

All executable files in this folder will appear in the Scripts menu. Choosing a script from the menu will run that script.

When executed from a local folder, scripts will be passed the selected file names. When executed from a remote folder (e.g. a folder showing web or ftp content), scripts will be passed no parameters.

What nautilus script specific variables can I use?

In all cases, the following environment variables will be set by Nautilus, which the scripts may use:

  • NAUTILUS_SCRIPT_SELECTED_FILE_PATHS
    # newline-delimited paths for selected files (only if local)
  • NAUTILUS_SCRIPT_SELECTED_URIS
    # newline-delimited URIs for selected files
  • NAUTILUS_SCRIPT_CURRENT_URI
    # URI for current location
  • NAUTILUS_SCRIPT_WINDOW_GEOMETRY
    # position and size of current window
# from Ubuntu 14.04 Nautilus does not have split view (extra pane), so these variables (most likely) will not work:
  • NAUTILUS_SCRIPT_NEXT_PANE_SELECTED_FILE_PATHS
    # newline-delimited paths for selected files in the inactive pane of a split-view window (only if local)
  • NAUTILUS_SCRIPT_NEXT_PANE_SELECTED_URIS
    # newline-delimited URIs for selected files in the inactive pane of a split-view window
  • NAUTILUS_SCRIPT_NEXT_PANE_CURRENT_URI
    # URI for current location in the inactive pane of a split-view window
How do these variables work? 

To test what these variables do you might use this nautilus script:
#!/bin/bash
# test your nautilus variables
touch $HOME/nautilustesting.txt
echo "SELECTED_FILE_PATHS: " "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS" >> $HOME/nautilustesting.txt
echo "SELECTED_URIS: " "$NAUTILUS_SCRIPT_SELECTED_URIS"  >> $HOME/nautilustesting.txt
echo "CURRENT_URI: " "$NAUTILUS_SCRIPT_CURRENT_URI" >> $HOME/nautilustesting.txt
echo "WINDOW_GEOMETRY: " "$NAUTILUS_SCRIPT_WINDOW_GEOMETRY" >> $HOME/nautilustesting.txt
echo " " >> $HOME/nautilustesting.txt

How to use these variables?

The variables you get will look something like this (in case of selecting 4 files with spaces in the names):
SELECTED_FILE_PATHS:  /home/username/.gnome2/nautilus-scripts/Screen rotate/Set screen inverted
/home/username/.gnome2/nautilus-scripts/Screen rotate/Set screen left
/home/username/.gnome2/nautilus-scripts/Screen rotate/Set screen normal
/home/username/.gnome2/nautilus-scripts/Screen rotate/Set screen right (notes)
SELECTED_URIS:  file:///home/username/.gnome2/nautilus-scripts/Screen%20rotate/Set%20screen%20inverted
file:///home/username/.gnome2/nautilus-scripts/Screen%20rotate/Set%20screen%20left
file:///home/username/.gnome2/nautilus-scripts/Screen%20rotate/Set%20screen%20normal
file:///home/username/.gnome2/nautilus-scripts/Screen%20rotate/Set%20screen%20right%20(notes)
CURRENT_URI:  file:///home/username/.gnome2/nautilus-scripts
WINDOW_GEOMETRY:  1022x690+0+1024

How to read nautilus selected file paths with spaces into a bash array?

To have a use of them as input file path for example imagemagick, I'll have to deal with the spaces, because these command line programs usually take "file path" as input and do not take "file URI" as input, and file path may contain spaces.

The FAQ of the G-Scripts site suggests some ways to handle this:
  1. protect your variable with double quotes: instead of $1 use "$1"
  2. process the filenames with SED:
    files=`echo "$1" | sed 's/ /\\ /g'`
  3. process the filenames with AWK and SED:
    quoted=$(echo -e "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS" | awk 'BEGIN {FS = "\n" } { printf "\"%s\" ", $1 }' | sed -e s#\"\"##); eval "your-program $quoted"
Actually, for me NONE of the above worked.
I found my solution in a stackoverflow post. It uses the IFS value to deal with the filenames. I read somewhere that using the IFS is an inelegant way to deal with field separators, and one should use AWK FS variable instead.

My solution: 

This is to use with nautilus scripts:
IFS=$'\n' read -d '' -r -a filelist < <(printf '%s\n' "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS"); unset $IFS
This is to use with my image manipulation scripts (where the script file is located in the same folder as the to-b-manipulated files):
IFS=$'\n' read -d "" -r -a filelist < <(find -iname "*.jpg" | sort); unset $IFS
When you want to call the elements of the array, you'll have to put them in double quotes, like
for i in "${filelist[@]}" 
do echo "$i"
done
Google search keywords to find the solution:

  • escape space in bash script
  • awk fs line break
  • sed change space to newline
  • escape space in bash script with sed
  • internal field separator
  • bash read file names into array
  • bash read space file names into array
  • echo into array bash
  • while read output array bash


Nincsenek megjegyzések: