Você pode usar um widget zle para fazer isso.
Defina o widget
Digite isto na linha de comando (ou insira-o no seu ~/.zshrc
, então é permanente):
accept-line-with-histmod() {
if [[ $BUFFER[1,3] == "?\!:" ]]; then
local loc mod
loc=${${(s.:.)BUFFER}[2]}
mod=${${(s.:.)BUFFER}[3]}
zle up-history
BUFFER="${${(z)BUFFER}[1,$((loc))]} $mod ${${(z)BUFFER}[$((loc+2)),-1]}"
CURSOR=$#BUFFER
else
zle accept-line
fi
}
zle -N accept-line-with-histmod
bindkey "^M" accept-line-with-histmod
Como usar?
A sintaxe é um pouco diferente da que você propôs, mas não muito (adicionei um ponto de interrogação na frente, para que a análise seja mais fácil). Demo ( $
é o prompt):
$ /long/path/to/bin -a foo -b 2 -c 3 -d 4 foo | gunzip -c | less
[...]
$ ?!:9:bar
$ /long/path/to/bin -a foo -b 2 -c 3 -d 4 bar | gunzip -c | less
Como funciona!
Este widget está ligado à chave ENTER
, substituindo a ligação de chave padrão de accept-line
, portanto, ele é executado toda vez que você pressiona entrar.
Primeiro, o widget verifica se a linha de comando começa com ?!:
; a variável $BUFFER
contém a linha de comando completa. Se não , o widget usual accept-line
é executado, resultando no comportamento padrão.
Mas se a linha começar com ?!:
, os argumentos ( ?!:POSITION:REPLACEMENT TEXT
) serão armazenados nas variáveis $loc
e $mod
, resp. [$ {$ {(s.:.)BUFFER}[2]} divide a linha de comando ( BUFFER
) em dois pontos ( (s.:.)
) e pega a segunda palavra ( [2]
)]
Agora, ele relembra a última linha do histórico ( zle up-history
) que agora reside em $BUFFER
. (Se você quiser lidar com eventos mais antigos, então você deve expandir o widget aqui!)
Então basicamente faz o mesmo que você fez no seu manual, construindo a linha de comando atual da antiga. (O deslocamento de 1 é porque o índice de matrizes começa em 1, mas o índice na expansão de histórico em 0).
Finalmente, o cursor é colocado no final da nova linha de comando, esperando que você confirme a execução.
Observações : Obviamente, não há tratamento de erros, então tenha cuidado! Eu também não testei com linhas de comando muito complexas. Pode ou não trabalhar com eles.
Como alternativa, você pode estar interessado na pesquisa & substitua a sintaxe da expansão do histórico:
$ echo foo
$ !:s/foo/bar
Ou o r
incorporado
$ echo foo
$ r foo=bar
No entanto, isso não é possível com o seu exemplo na pergunta, já que não existe um único.