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

HappyFace
  • 1,493
  • 9
  • 21

1 Answers1

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
}
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • 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 03 '18 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`. – Stéphane Chazelas Sep 03 '18 at 11:10
  • BTW, I don't understand why `eval '^(#b)E(?)^E${(l:2::0:)$((match[1]+1))}'` is failing. Shouldn't `eval`ing a command be just like typing it? and thank you, things finally worked out. :D – HappyFace Sep 03 '18 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` – Stéphane Chazelas Sep 03 '18 at 13:49
  • 1
    @HappyFace, see also the edit for possible improvements to your approach. – Stéphane Chazelas Sep 03 '18 at 14:00
  • Thanks! I was actually just googling to see how I could put it on the history. :))) – HappyFace Sep 03 '18 at 14:12