转义bash
别名在任何非来源且正常运行的 shell 脚本中是否有意义?
考虑最简单的情况,许多用户使用(in或)ls
重新定义其功能,例如:alias
.bashrc
.bash_aliases
alias ls='\ls --color=auto --group-directories-first'
然后假设我调用一个包含函数的 shell 脚本,例如:
list_sata_devices ()
{
\ls -1 /dev/sd?
}
正如你注意到的,我强迫原本的 ls
与\ls
,但我想知道是否有必要这样做?
当然,可以不使用 来编写它ls
,例如:
list_sata_devices ()
{
printf '%s\n' /dev/sd?
}
但我仍然犹豫可能存在什么差异。
答案1
alias ls='\ls --color=auto --group-directories-first'
不需要反斜杠,shell 不会陷入这样一个微不足道的循环:
替换文本的第一个单词会进行别名测试,但与正在扩展的别名相同的单词不会再次扩展。
然后假设我调用一个包含函数的 shell 脚本,例如:
list_sata_devices () { \ls -1 /dev/sd? }
如果它是一个 shell 脚本,即非交互式 shell,那么默认情况下别名是禁用的:
当 shell 非交互式时,别名不会展开,除非使用 shopt 设置 Expand_aliases shell 选项(请参阅 Shopt 内置)。
该脚本需要显式启用它们(shopt -s expand_aliases
)即使它这样做(无论出于何种原因),它也不会继承交互式 shell 中设置的任何别名,并且非交互式 shell 也不会读取例如.bashrc
,因此它不会从那里获取它们。非交互式 shell 会读取名为的文件$BASH_ENV
不过,所以也许不要在那里设置别名。
因此,这里也不需要反斜杠。
list_sata_devices () { printf '%s\n' /dev/sd? }
嗯,这是一个不同的命令。实际上效果不大,但ls
如果打印到终端,可能会以不同的方式处理某些特殊字符。
无论如何,巴什能 导出和继承 功能通过环境,这可能会弄乱脚本,但通常不会意外地这样做。
答案2
您的上下文是这样的,您希望在其环境中执行脚本,而不是在调用 shell 中获取它。
在这种情况下,无需转义脚本中的任何命令名称,即使该名称之前可能已使用别名。
如果不获取包含别名的定义的文件,别名不会转移到脚本环境中。
脚本不是交互式 shell,因此在脚本中定义别名的有用性值得怀疑,因为它们的作用主要是交互式上下文中的便利性之一。作为(希望)易于记住的缩写,cmd 别名基本上简化了人与机器之间的交互(阅读“它们使您无需记住大量长命令并在终端窗口中键入”)。
因此,出于多种原因,我通常不会在脚本中使用预定义别名:(i) 脚本可读性,以及 (ii) 保持对脚本及其功能的完全控制,而无需使用外部别名来定义脚本中的内容和不包含的内容。你的脚本。想象一下,根据其他地方定义的别名编写脚本,几个月或几周后修改该别名定义,而不记得您的旧脚本实际上依赖于它......默认情况下,别名不会转移到在子中执行的脚本中,这是一件好事。贝壳。
此外,从man bash
,当在函数内部时,只有在读取函数并变得可用后才会扩展别名后该函数被执行。因此,在实践中,如果您要在脚本中定义别名(我通常不会,但可能存在特殊用例),最好的位置是在不同的行上多于函数或任何使用所述别名的 cmd(这里考虑函数被执行 shell 视为命令)。
最后,与脚本无关,@muru 的最上面的评论是完全有效的,在 Bash 手册中也可以找到。如果别名的扩展包含其自己的名称,则扩展中该别名名称的出现不会导致该名称的新扩展,等等。这将导致无限递归。所以你可能会看到但永远不需要写:alias ls='\ls --color=auto --group-directories-first'
。相反,只需写:alias ls='ls --color=auto --group-directories-first'
。
然而,转义以前的别名可能很有用,但在不同的情况下,例如:
alias ls='ls -A --color=auto --group-directories-first'
alias ll='\ls -l --color=auto'
在上面的情况下,如果您没有在别名ls
中转义ll
,它将包括在定义别名的第一行中定义的标志和选项ls
,您可能想要也可能不想要。这告诉您链接别名是可以的,而递归则不行。
编辑:回答你关于ls -1 <foo*>
和之间区别的最后一个问题printf '%s\n <foo*>
。
例如,在运行 Gnu Bash v5.1.4 的特定 x86_64 机器中:
$ time for i in $(seq 10000); do \ls -1 /dev/sd* 1> /dev/null; done
real 0m17.420s
user 0m10.910ss
sys 0m7.598s
$ time for i in $(seq 10000); do printf '%s\n' /dev/sd* 1> /dev/null; done
real 0m0.574s
user 0m0.285s
sys 0m0.287s
ls
即使它是内置的,执行也很耗时,因为怎么运行的。我不擅长其实现的细节,尽管除了lstat()
涉及文件权限时它使用的事实之外。