bash && zsh: referencing / repeating a previous command line *argument* while still crafting the same line
Let's say I am entering some complex command that repeats one of the command line arguments, or some variation of one of the arguments, and let's say I'm dealing with very long and complex command line arguments.
It would be one of the below patterns, where "foo" is the very long and cumbersome argument and "foo2" is a variation of it where the "2" character is appended.
$ ./binary "foo" "foo"
[...]
# OR
$ ./binary "foo" "foo2"
[...]
# OR
$ ./binary -x "foo" -y "foo"
[...]
# OR
$ ./binary -x "foo" -y "foo2"
[...]Is there some way to have bash / zsh auto complete the second instance of "foo" without having to manually copy & paste it?
Basically, I'm looking for something like the below, but in the same command line instead of referencing a previous command line.
$ echo one two three > /dev/null && echo !:2 !{:2}2
two two2 2 Answers
Possible (suboptimal) solution:
# not ideal because it requires me to realize in advance
# that I will have to repeat "foo" on the same line
$ (FOO="foo"; ./binary "${FOO}" "${FOO}2") "auto complete" is probably not the way to go, but you can use the readline functions in bash (zsh must have something similar). For example,
_myinsert() { local TOADD=${READLINE_LINE:0:$READLINE_POINT} TOADD=${TOADD% } TOADD=${TOADD##* } TOADD=" ${TOADD}2" READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}${TOADD}${READLINE_LINE:$READLINE_POINT}" READLINE_POINT=$(($READLINE_POINT + ${#TOADD}))
}
# cannot put this in ~/.inputrc
bind -x '"\C-xx":_myinsert'This calls the function _myinsert when you type Control-X X (arbitrary binding) at some point in the input line. The index of that point is placed by bash in $READLINE_POINT, and the entire input line is in $READLINE_LINE. You can then extract the last word before point from the string, manipulate it as you wish, and create a new entire input line in the same variable before returning. Remember to also update the index point to take into account the change too.
One little-known default bash binding I use a lot is yank-last-arg, bound to Meta-. (in emacs mode at least). It copies the last word from the previous command. When I realise I need to duplicate the last (long) word, I add a # to the start of the line, press return, press up-arrow to get the command again, remove the hash, go to the end with control-E, and use yank-last-arg.