0
zsh history searchからの改行の扱い
2024-12-09

自分はzshrc上でpecoを使ってzsh_historyからの検索しているが、実行コマンドに改行が含まれていた場合にうまく実行できない状態だった

いろいろ調べて対応してみた記録

とりあえずいったんこうしたって感じなので今のところはベストだがまたうまくいかないケース出てくるかもしれない

前提となる設定(before)

  • zshrc
function peco-select-history() {
    local tac
    if which tac > /dev/null; then
        tac="tac"
    else
        tac="tail -r"
    fi
    BUFFER=$(\history -n 1 | \
        eval $tac | \
        peco --query "$LBUFFER")
    CURSOR=$#BUFFER
    zle clear-screen
}
zle -N peco-select-history
bindkey '^r' peco-select-history

よくあるCtrl+rで履歴検索して実行するやつ

改行が含まれるケース

行継続

バックスラッシュで行を継続させるよとシェル上では指示して改行して可読性あげるパターン

Actionsとかでワンショットのコマンド考えるときとかこういうのよくやる

echo 'This is a long line hoge' \
| grep "long" \
| awk '{print $NF}'

履歴上はこのようになる

echo "This is a long line" \\n| grep "long" \\n| awk '{print $NF}'

で、普通に実行するとエラーになってしまう

grep: \n: No such file or directory
  • 対応は履歴呼び出し時に置換させる
sed s'/ \\\\n/ /g'

かなり決め打ちではあるがしょうがない…

スクリプト

while read -r line; do
    echo "行の内容: $line";
done < /path/to/file

シェルスクリプトをそのまま貼り付けて実行するパターン

履歴呼び出し時

while read -r line; do\n echo "行の内容: $line"\ndone < /path/to/file

実際は下記じゃないと動かない

while read -r line; do echo "行の内容: $line"; done < /path/to/file

行末に;が入るパターンと入らないパターンがあり、入らなくても改行を入れればよしなに解釈してくれるパターンが存在する

そのため決め打ちで変換すると微妙だな…ということでzle redisplay+printfの組み合わせで、BUFFERに改行込みの表示をさせて貼り付けなり入力した状態と同じ状態を保つことに成功した

結果

alt

最終的な設定(after)

  • zshrc
function peco-select-history() {
    local tac
    if which tac > /dev/null; then
        tac="tac"
    else
        tac="tail -r"
    fi
    selected=$(\history -n 1 | \
        eval $tac | \
        peco --query "$LBUFFER" | \
        sed s'/ \\\\n/ /g')
    BUFFER=$(echo "${selected}")
    zle redisplay
    CURSOR=$#BUFFER
}
zle -N peco-select-history
bindkey '^r' peco-select-history

おわり

1つ目の行継続の方もzle redisplay+printfパターンで解決したかったが、いろいろ試してもBUFFER上に\をどうしても表示させられなかったため断念

とりあえずは改行含めたコマンドも履歴から再現できるようになったので快適度は上がった

誰かよい方法知っていたら教えてほしいです…

0

Profile

swfz
swfz
日々学んだことを残していく
Today I Learned
コード片置き場

Account

RSS

Powered by Pixela
© 2024. swfz