HOWTO: Iterate Selected Files (Project Drawer)
Ken Scott wrote a command to delete files selected in the project drawer from subversion (which is now part of the Subversion bundle.)
This command makes use of the TM_SELECTED_FILES
environment variable, but the contents of that variable is a little special, as it contains multiple file names, and he wanted to present these nicely.
So let us look at how to do that.
A variable like TM_FILEPATH
contains the exact path of the current file. So one can (in shell scripts) use it as "$TM_FILEPATH"
, here the quoting is important, so that the shell doesn’t parse the result after expanding the variable (basically doing word-splitting according to the value of the input-field-separator (IFS) variable).
But if we have selected /tmp/foo.txt
and /tmp/bar.txt
in the project drawer, the value of TM_SELECTED_FILES
will be:
'/tmp/foo.txt' '/tmp/bar.txt'
That is, it lists the filenames as single-quoted and space separated, as you would type them in the shell, had you been using an interactive shell.
So what we want is to expand the variable and then re-execute the entire line. This could be done as:
echo svn rm "$TM_SELECTED_FILES"|sh
Here we use echo
to create the actual command line we want to execute, and then feed that to sh
(the shell interpreter). But a better way is to put eval
first on the line. This will make the shell re-evaluate the line, after performing the initial variable expansions:
eval svn rm "$TM_SELECTED_FILES"
A follow-up question would be, what if we wanted to do something with each of the files listed in TM_SELECTED_FILES
. For that, we can use bash arrays. An array is specified like below:
arr=(foo bar fud)
After that, arr
will be a normal variable. We can use ${arr[n]}
for the n’th element, or ${#arr[@]}
for number of elements in the array. To iterate over the elements we can therefor do:
arr=(foo bar fud)
for (( i = 0; i < ${#arr[@]}; i++ )); do
echo "element $i is ${arr[$i]}"
done
We still lack to convert the TM_SELECTED_FILES
variable into an array. Similar to above, we use the variable where we want the list, and prefix the line with eval
to have it re-evaluate the line, after having performed the variable expansion:
eval arr=("$TM_SELECTED_FILES")
So to iterate all selected files and output the basename, we end up with something liek this:
eval arr=("$TM_SELECTED_FILES")
for (( i = 0; i < ${#arr[@]}; i++ )); do
file=${arr[$i]}
base=$(basename "$file")
echo "selected file number $i is $base"
done