In zsh
, by default all the widgets that operate on words including the transpose-words
one bound by default to Alt+T in emacs
mode work on words that are defined as sequences of alnum+$WORDCHARS
characters.
The default value of $WORDCHARS
has *?_-.[]~=/&;!#$%^(){}<>
, so includes /
, so should be fine for you to transpose paths as long as those paths don't include characters outside of that. That won't work for paths that contain things like :
, @
, ,
... or are quoted though.
But you could use the select-word-style
framework to change the definition of word on-demand.
If you add:
autoload -U select-word-style
zle -N select-word-style
bindkey '\ez' select-word-style
to you ~/.zshrc
, then upon pressing Alt+Z, you'll get the choice:
Word styles (hit return for more detail):
(b)ash (n)ormal (s)hell (w)hitespace (d)efault (q)uit
(B), (N), (S), (W) as above with subword matching
?
After pressing "return for more detail":
(b)ash: Word characters are alphanumerics only
(n)ormal: Word characters are alphanumerics plus $WORDCHARS
(s)hell: Words are command arguments using shell syntax
(w)hitespace: Words are whitespace-delimited
(d)efault: Use default, no special handling (usually same as `n')
(q)uit: Quit without setting a new style
so pressing S would allow you to transpose two shell words (so including those containing quoted spaces or command substitutions...) with Alt+T (or delete one with Ctrl+W, move back one with Alt+B, etc).
See
info zsh select-word-style
for details (assuming the zsh documentation has been installed on your system (zsh-doc
package on Debian and derivatives)).
You'll find a section there that looks like it has been especially written for you which you can adapt to specify how you want transpose-words
to behave whenever the cursor is on a filename or in-between words, etc:
Here are some examples of use of the word-context style to extend
the context.
zstyle ':zle:*' word-context \
"*/*" filename "[[:space:]]" whitespace
zstyle ':zle:transpose-words:whitespace' word-style shell
zstyle ':zle:transpose-words:filename' word-style normal
zstyle ':zle:transpose-words:filename' word-chars ''
This provides two different ways of using transpose-words depending
on whether the cursor is on whitespace between words or on a
filename, here any word containing a /. On whitespace, complete
arguments as defined by standard shell rules will be transposed.
In a filename, only alphanumerics will be transposed. Elsewhere,
words will be transposed using the default style for
:zle:transpose-words
.
For instance, with:
autoload -U select-word-style
zle -N select-word-style
bindkey '\ez' select-word-style
select-word-style normal
zstyle :zle:transpose-words word-style shell
transpose-words
would work with shell words always while all other word widgets would use the normal definition of word, and you could still use Alt+Z to change it (for widgets other than transpose-words
).
Best Answer
The
fc
built-in command allows you to extract commands from the history using a number of criteria (seeman zshbuiltins
for details).fc
stands for “fix command”, and when invoked with no parameters it opens an editor with the last command entered. You can use all your editor’s features to change the command, and when you save and exitzsh
runs the fixed command. The editor used by default isvi
, but that can be overridden using theEDITOR
shell variable or, if you want to use a specific editor with thefc
command,FCEDIT
.fc
has many options to manipulate history beyond the last command, some of which provide exactly the capabilities you're asking for.The
-l
option “lists” the contents of the history. By default it lists the last 16 commands, but you can specify lower and upper boundaries, as indices in the history or even as the starting text of a command. Negative indices work back from the last command, so to extract the last 15 lines:By default
fc -l
includes history indices as the first column of its output. Once you have the exact range you want,-n
drops the numbers so:will extract only those lines (from 12 back to 5 back) in a format suitable for a script.
Using commands as boundaries can be very useful:
lists all the history starting with the last
rm
and ending with the lastls
(so there will be a singlerm
command in the output but there may be multiplels
commands).There are many other options, such as adding timestamps, replacing portions of commands, loading and saving portions of history, switching entire history stacks...