执行脚本时转义脚本中的 shell 别名有用吗?

执行脚本时转义脚本中的 shell 别名有用吗?

转义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()涉及文件权限时它使用的事实之外。

相关内容