4

I want this to work (it needs extendedglob and histsubstpattern):

alias ri='^(#b)E(?)^E${(l:2::0:)$((match[1]+1))}'

But it doesn't:

$ alias sss='^(#b)E(?)^E${(l:2::0:)$((match[1]+1))}'                                               
$ echo /Users/evar/Downloads/Video/Teenage_Mutant_Ninja_Turtles_2003_S02E01_DVDRip_30NAMA.mkv
/Users/evar/Downloads/Video/Teenage_Mutant_Ninja_Turtles_2003_S02E01_DVDRip_30NAMA.mkv
$ sss                                                                                             
zsh: command not found: Pocket

I wouldn't mind using a function instead of an alias, but the result was the same.

I even tried export ss='^(#b)E(?)^E${(l:2::0:)$((match[1]+1))}' and then doing $ss, but that failed with zsh: command not found: ^(#b)E(?)^E${(l:2::0:)$((match[1]+1))}.

Using eval '^(#b)E(?)^E${(l:2::0:)$((match[1]+1))}' also fails with zsh: command not found: Pocket.

Update: Related (possibly duplicate) questions found:

Alternative of bash's `history -p` in zsh?

https://stackoverflow.com/questions/27494753/how-to-get-last-command-run-without-using

https://stackoverflow.com/questions/48696876/using-history-expansion-in-a-bash-alias-or-function

1 Answer 1

3

You can't, history expansion happens before alias or parameter expansion.

I personally hate history expansion and is the first thing I disable.

Here, instead of aliasing a history expansion, I'd suggest creating a widget that increments a E<n> number left of the cursor:

increment-episode() {
  emulate -L zsh
  setopt extendedglob
  LBUFFER=${LBUFFER/(#b)(*E)(<->)/$match[1]${(l:${#match[2]}::0:)$((match[2]+1))}}
}

zle -N increment-episode

bindkey '\e+' increment-episode

And then, you just press Up and then Alt++ and you have a visual feedback of what's going on at every stage and can undo/redo/adapt at will, and not work blindly like with csh history expansion (a feature from the 70s that IMO made sense then but not so much now that we have faster and more capable terminals and line-editors).

But if you really wanted to blindly evaluate the code in the previous command in the history with the number after E incremented, you could do:

rerun-with-next-episode() {
  emulate -L zsh
  setopt extendedglob
  local new
  new=${${history:0:1}/(#b)E(<->)/E${(l:${#match[1]}::0:)$((match[1]+1))}}

  # display it
  print -ru2 -- $new

  # put it on the history
  print -rs -- $new

  # evaluate it
  eval -- $new
}
6
  • Is the setopt extendedglob locally scoped? If not, can it not be locally scoped? And why does the history expansion bother you enough to warrant disabling? Any specific cons?
    – HappyFace
    Sep 3, 2018 at 11:08
  • 1
    @HappyFace, my main concern is unwanted expansions of !s. emulate -L resets the options to a sane default and makes options (including ones set later on) locally scoped. If you want extendedglob set globally (which I'd recommend for interactive use), just add setopt extendedglob to your ~/.zshrc. Sep 3, 2018 at 11:10
  • BTW, I don't understand why eval '^(#b)E(?)^E${(l:2::0:)$((match[1]+1))}' is failing. Shouldn't evaling a command be just like typing it? and thank you, things finally worked out. :D
    – HappyFace
    Sep 3, 2018 at 13:43
  • 1
    @HappyFace, history expansion is only done upon input lines coming from zle. Think of the history number for instance. It wouldn't make sense in eval Sep 3, 2018 at 13:49
  • 1
    @HappyFace, see also the edit for possible improvements to your approach. Sep 3, 2018 at 14:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .