适当的zsh shell命令转义

3

我有一个非常强大的技巧,我正在尝试用它来保存我曾经输入的每个命令:

function zshaddhistory() {
    COMMAND_STR=${1%%$'\n'}
    [[ ( -z $COMMAND_STR ) || ( $COMMAND_STR =~ hist(ory)? ) || \
        ( $COMMAND_STR =~ ^l(s\|l\|a)?$ ) || \
        ( $COMMAND_STR =~ ^(d\|gd\|git\ diff\|glp\|gg)$ ) \
    ]] && return 1
    # do not do anything on common commands

    # do the needful
    echo "$PWD; $COMMAND_STR; $TTY@$HOST@$(date +%s.%N)" >> ~/.zsh_enhanced_history

    # rest is supposedly "default" zshaddhistory() (except it ain't)
    print -Sr ${COMMAND_STR}
    fc -p
}

这个东西真的很难搞定(比如使用print -S以避免破坏!$等),但现在它对我来说基本上已经运行得很正常了。

然而,我注意到一些保存内容的轻微不一致性,因为我正在构建一个Python脚本,用于以彩色列打印保存的命令。

举个例子:

% echo "\\"
\

现在,~/.zsh_enhanced_history 包含以下内容:
/home/slu/util; echo "\"; /dev/pts/20@1376064693.136746657

因此,它将echo "\\"(产生输出\)保存为echo "\"(这不是一个格式正确的命令)。同样地,命令echo "\n"被保存为带有文字换行符,因此它将在历史文件中占用两行。实际上就是这种行为导致我最初发现了它,因为我的Python正则表达式会为每个包含换行符的命令产生多个解析失败的结果。我尝试将printf "%q" "$COMMAND_STR"的输出保存为$COMMAND_STR,这似乎确实解决了换行符问题,甚至可能是反斜杠,但它会转义空格和双引号,所以也是错误的。常规的~/.zsh_history文件没有这个问题,它包含了完全按照输入的命令。因此,在我的zshaddhistory中,我没有做出正确的转换。也许有额外的shell字符串评估需要防止。需要一些来自zsh专家的帮助!

你确定要使用 print -S 吗?printzsh 内置命令 建议使用 -s - simont
是的!如果您不使用“-S”,它将破坏!$和其他相关内容。这非常令人沮丧。 - Steven Lu
2个回答

0

这个例子来自zsh邮件列表,使用了print。将其与您的函数结合使用,得到如下结果:

zshaddhistory () {
    # Print to the default history file with the newline stripped. 
    print -sr -- "${1%%$'\n'}"

    # Ignore common commands. 
    COMMAND_STR=${1%%$'\n'}
    [[ ( -z $COMMAND_STR ) || ( $COMMAND_STR =~ hist(ory)? ) || \
        ( $COMMAND_STR =~ ^l(s\|l\|a)?$ ) || \
        ( $COMMAND_STR =~ ^(d\|gd\|git\ diff\|glp\|gg)$ ) \
        ]] && return 1


    # Switch history contexts
    fc -p ~/.zsh_history_detail
    # Push the current line into the current history context with newline stripped and user / time appended. 
    print -sr -- "${1%%$'\n'} ### ${PWD} $(date '+%Y-%m-%d %R')"
    return 1
}

这似乎是您想要的。我已经测试过使用echo "\\"echo "\n"

charizard% cat ~/.zsh_history_detail                               
cat: /Users/simont/.zsh_history_detail: No such file or directory
charizard% echo "\\"                                               
\
charizard% cat ~/.zsh_history_detail                               
: 1376117319:0;echo "\\" ### /Users/simont 2013-08-10 16:18
charizard% cat "\n"      # This was an oopsie                      
cat: \n: No such file or directory
charizard% echo "\n"                                               


charizard% echo "\\"                                               
\
charizard% cat ~/.zsh_history_detail                               
: 1376117319:0;echo "\\" ### /Users/simont 2013-08-10 16:18
: 1376117334:0;cat "\n" ### /Users/simont 2013-08-10 16:18
: 1376117339:0;echo "\n" ### /Users/simont 2013-08-10 16:18
: 1376117343:0;echo "\\" ### /Users/simont 2013-08-10 16:19

我不知道你的意思是什么:

但它会转义空格和双引号,所以也是错误的

因此我无法进行测试。


嗯,这似乎表明使用 print 可能是将反斜杠和换行符正确插入历史文件的特殊方法(即我的 >> 输出重定向是罪魁祸首,我没有考虑到)。至于“空格和双引号”,如果你仔细阅读,那是指在引入 printf '%q' 时会发生什么。 - Steven Lu

0

我找到了问题的根源,这是通过比以前更仔细地阅读zsh manpage部分来明显地表现出来的。

print下:

          -r     Ignore the escape conventions of echo.

所以,我只需要对我的zshrc文件进行一处更改(我的~/.zshrc是符号链接到这个zshrc文件),即可完成:

diff --git a/zshrc b/zshrc
index 5e72133..af97c35 100644
--- a/zshrc
+++ b/zshrc
@@ -68,7 +68,7 @@ function zshaddhistory() {
     # do not do anything on common commands

     # do the needful
-    echo "$PWD; $COMMAND_STR; $TTY@$HOST@$(date +%s.%N)" >> ~/.zsh_enhanced_history
+    print -r "$PWD; $COMMAND_STR; $TTY@$HOST@$(date +%s.%N)" >> ~/.zsh_enhanced_history

     # rest is "default" zshaddhistory()
     print -Sr ${COMMAND_STR}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接