I need to find the last argument of a command, check if it's a valid file name, if so I pass that to fre
which is part of my command-completion toolchain. The code I have works except in one case: if the last argument of the command is a valid file name containing embedded spaces. I can't see how to deal with this. Any ideas? Here's the code:
fre_preexec () {
local tmpcmd="$1"
local cand_fname="${tmpcmd##* }"
[ -f "$cand_fname" ] && fre --add "$cand_fname"
}
According to the documentation, for preexec
$1
contains the entire command string.
Thanks in advance.
Edit: I managed to get something that snagged a file name, but I can't get that to past the -f
test:
local tmpcmd="$1"
local cand_fname="${tmpcmd##*[^\\] }"
echo "cand_fname ${cand_fname}"
# [ -f "$cand_fname" ] && fre --add "$cand_fname"
[ -f "$cand_fname" ] && echo fre --add "$cand_fname"
If the command is ls -l fred\ bill.txt
, this prints
cand_fname fred\ bill.txt
but does not echo
anything. I can't figure that part out.
You need a mix of the z
parameter expansion flag to split a string according to normal shell rules, and the Q
flag to handle removing the literal backslash (And other quote related characters) left in the arguments to preexec
. For example:
#!/usr/bin/env zsh
preexec () {
local tmpcmd="$3"
# Note the nested expansion
local cand_fname=${(Q)${(z)tmpcmd}[-1]}
print "cand_fname: $cand_fname"
[ -f "$cand_fname" ] && echo fre --add "$cand_fname"
}
ls -l fred\ bill.txt
and in action:
$ touch "fred bill.txt"
$ zsh demo.sh
cand_fname: fred bill.txt
fre --add fred bill.txt
-rw-r--r-- 1 x x 0 Feb 7 05:07 'fred bill.txt'