bash别名中的转义字符[重复]

Posted

技术标签:

【中文标题】bash别名中的转义字符[重复]【英文标题】:Escaping characters in bash alias [duplicate] 【发布时间】:2017-08-14 16:23:03 【问题描述】:

这是别名:

     # make a tmux session in working dir with the name of the dir
     alias th='tmux new -s $(pwd | tr '\/' '\n' | tail -n 1)'  

由于转义字符或别名中的' 单引号,它不起作用。打印出来

    $ type --all th
    th is aliased to `tmux new -s $(pwd | tr / n | tail -n 1)'

看起来它只是去掉了'\

我最终通过将单引号更改为双引号来修复它。

     # make a tmux session in working dir with the name of the dir
     alias th='tmux new -s $(pwd | tr "\/" "\n" | tail -n 1)'  

我的问题是之前的工作是如何工作的?不应该 bash 抛出解析错误。

【问题讨论】:

并没有真正回答您的问题,但由于您标记了 bash,我会将 $(pwd | ...) 换成 "$PWD##*/" 相关:***.com/questions/20111063/… 和 ***.com/questions/40814087/… 顺便说一句,虽然 通常 echo 是一个非常糟糕的调试工具选择(有几种方法可以修改它打算按原样显示的数据),它实际上就足够了在这里显示问题:您会看到 echo 'tmux new -s $(pwd | tr '\/' '\n' | tail -n 1)' 没有显示任何内部引号,因为 - 这些引号是句法而不是文字 - 它们在解析过程中被消耗。 【参考方案1】:

最佳建议:不要。

改用函数:

th()  tmux new -s "$PWD##*/" "$@"; 

$PWD##*/ 是一个parameter expansion,它会从$PWD 的内容中删除直到最后一个/ 的所有内容。


替代方法:文字引号

您的原始代码中的问题是它包含 syntactic 引号 - 由 shell 解析以确定单引号解析规则的开始和结束位置 - 在您真正想要的地方literal 引号,被视为数据(因此成为别名的一部分)。

使这些引号字面化的一种方法是改用$'' 引号形式,这使您可以使用文字反斜杠来转义内部引号,使它们成为文字而不是句法:

alias th=$'tmux new -s $(pwd | tr \'\\\/\' \'\\n\' | tail -n 1)'

请注意,在使用$'' 时,文字反斜杠也需要转义(因此,写为\\ 而不是\)。


解释:为什么

POSIX shell 语言中的字符串引用是逐个字符确定的。因此,在以下情况下:

'$foo'"$((1+1))"baz

...$foo 是单引号,因此被视为文字字符串,$((1+1)) 是双引号,因此有资格被视为算术扩展,baz 未加引号——即使这三个其中的这些被连接起来形成一个单词 ($foo2baz)。

这些引号都是 syntactic -- 它们是对 shell 的指令 -- 而不是 literal (这意味着它们将是数据的一部分)字符串计算)。


这如何应用到您之前的命令

alias th='tmux new -s $(pwd | tr '\/' '\n' | tail -n 1)'  

...tr 参数中的单引号 end 单引号从别名的开头开始。因此,\/\n 在未引用的上下文中进行评估(其中\/ 变成了 /,而 \n 变成了 n)——因为如上所述,多个不同的引用子字符串可以连接成一个更大的字符串,你得到你之前的命令,而不是别名。

【讨论】:

【参考方案2】:

您嵌入的单引号没有被视为嵌入,它们终止了以前的字符串并盯着新的字符串。您的第一次尝试被视为tmux new -s $(pwd | tr\/、''、\n| tail -n 1) 的串联。将它们放在一起并处理转义,您会在type 命令的输出中看到您所看到的内容。

也值得考虑:https://unix.stackexchange.com/questions/30925/in-bash-when-to-alias-when-to-script-and-when-to-write-a-function

【讨论】:

所以 bash 别名只会连接字符串直到结束行?对我来说这是不直观的。感谢您清理一切。 @JohnStone 好吧,关键是这里没有标记空格(实际上我不小心把空格从字符串列表中删除了)。如果您在列表中的任何地方都有未转义/引用的空格,那么这些空格将被 bash 处理为不同的“单词”,在这里您只有一个单词,因为您有一个连续的字符串,其中一些部分被引用,而有些是裸字符串(比如\n @JohnStone, ...不仅仅是“一个 bash 别名”——在 POSIX 兼容的 shell 语言(不仅仅是 bash)中的 所有 字符串都遵循同样的规则。跨度>

以上是关于bash别名中的转义字符[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何转义任意字符串以用作 Bash 中的命令行参数?

如何转义变量中的特殊字符以在 bash 中提供命令行参数

Perl:转义字符串中的特殊字符以匹配正则表达式

如何将字符串中的“\t”拆分为两个单独的字符“\”和“t”? (如何拆分转义序列?)[重复]

Python中的HTML转义[重复]

Javascript函数调用。字符串中的转义引号[重复]