【问题标题】:proper zsh shell command escapement正确的 zsh shell 命令转义
【发布时间】:2013-08-09 16:18:29
【问题描述】:

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

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-string-eval 。

需要 zsh 专家的帮助!!

【问题讨论】:

  • 你确定要print -S吗? zsh builtins for print 建议使用 -s
  • 是的! 如果您不使用-S,它将破坏!$ 和朋友。超级沮丧。

标签: linux macos shell unix zsh


【解决方案1】:

zsh 邮件列表中的This example 使用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

我不明白你的意思:

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

所以我无法对此进行测试。

【讨论】:

  • Hmmmmm,所以,这似乎表明 print 的使用可能是保持反斜杠和换行符正确插入历史文件的特殊调味品(即我使用 >> 输出重定向是罪魁祸首,我没有考虑过)。至于“空格和双引号”,如果你仔细阅读,那是指将printf '%q' 带入图片时发生的情况。
【解决方案2】:

我找到了问题的根源,通过阅读 zsh 手册页部分比我以前更仔细地阅读了这一点。

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}

【讨论】:

    猜你喜欢
    • 2011-08-22
    • 1970-01-01
    • 1970-01-01
    • 2021-01-12
    • 2014-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-12
    相关资源
    最近更新 更多