为什么我的Bash脚本无法识别别名?


216

在我的~/.bashrc文件中包含两个定义:

  1. commandA,这是较长路径的别名
  2. commandB,它是Bash脚本的别名

我想使用这两个命令处理相同的文件,因此我编写了以下Bash脚本:


#!/bin/bash

for file in "$@"
    do
    commandA $file
    commandB $file
done

即使注销了会话并重新登录后,command not found运行该脚本时,Bash也会提示我两个命令都出错。

我究竟做错了什么?


10
顺便说一句,无需登录和注销即可识别别名。您只需要这样做source ~/.bashrc
tshepang 2010年

就我而言,我在关闭SSH代理并再次连接后添加别名后,通过SSH代理远程连接。
dav 2015年

别名是一种缩短命令的方法。(它们仅在交互式外壳中使用,而不在脚本中使用-这是脚本和交互式外壳之间的极少数差异之一。)
Kris Roofe

Answers:


117

首先,正如ddeimeke所说,默认情况下,别名不会在非交互式shell中扩展。

其次,.bashrc除非您设置BASH_ENV环境变量,否则非交互式外壳程序不会读取它。

但最重要的是:不要那样做!请?有一天,您将把该脚本移到未设置必要别名的地方,它将再次中断。

而是在脚本中设置环境变量并将其用作快捷方式:

#!/bin/bash

CMDA=/path/to/gizmo
CMDB=/path/to/huzzah.sh

for file in "$@"
do
    $CMDA "$file"
    $CMDB "$file"
done

5
该解决方案不适用于通常的alias用例。例如alias mv="mv -v --backup=numbered"
Evi1M4chine '16

@ Evi1M4chine:是的。至少在我还原了Gilles不必要的编辑之后。但是无论如何,最好对参数使用不同的变量。

1
嗯,请注意/ 周围缺少引号。。。除了在bash中为bash本身保留大写变量,而且确实有效之外,缺少引号让我真的很不舒服……还是谢谢。$CMDA$CMDB
Evi1M4chine '16

@ Evi1M4chine:嗯,什么?1.我本人在最近的编辑中删除了引号。2.您从哪里得到“保留给bash本身”?这将是我第一次听说。3.如果让您感到不安,那么首先感觉如何使用bash?无论如何,请按照我告诉您的方式为选项使用单独的变量。

1
@alvas:假定gizmo该路径不在路径上,或者存在具有相同名称但具有更高优先级的命令。否则,您可以首先简单地设置CMDA为普通gizmo格式。

161

如果您查看bash手册页,则会发现:

如果外壳不是交互式的,则别名不会扩展,除非使用shopt设置expand_aliases shell选项(请参阅下面的SHELL BUILTIN COMMANDS下的shopt说明)。

所以放一个

shopt -s expand_aliases

在您的脚本中。

在脚本中设置别名文件后,请确保来源文件。

shopt -s expand_aliases
source ~/.bash_aliases

7
我将其放在脚本中,但仍无法正常工作。同样的错误。
Zaid

5
添加shopt -s expand_aliases source ~/.bash_aliases非常适合我。通常,.bashrc中有一种交互式外壳程序检测形式,如下所示:# If not running interactively, don't do anything [ -z "$PS1" ] && return@Zaid,也许您想在源文件中进行检查。
弗兰克·舒伯特

1
优秀的!保存了我的脚本!:)很难在终端上阅读/搜索/浏览信息和手册页,以至于我很久以前就放弃了,可以在互联网上搜索...
Aquarius Power

2
奇怪的是,shopt -s expand_aliases不必在别名定义之前,而在别名使用之前。添加到@FrankSchubert:还可以使用$-其中包含外壳选项的交互式外壳检测,特别i是在外壳是交互式的情况下。
有效

2
这不是正确的答案...在脚本中添加别名不是答案。您~/.bash_aliases可能依赖于以前在交互式外壳上加载的其他内容...我发现的最接近的东西是将您的hashbang更改为“ #!/bin/bash -li仍然不完美”。理想情况下,您应该使用函数而不是别名。
Stefanos Kalantzis,

44

别名无法导出,因此在未定义别名的Shell脚本中不可用。换句话说,如果您~/.bashrc无法使用它们来定义它们your_script.sh(除非您~/.bashrc从脚本中获取资源,我不建议这样做,但是有一些方法可以正确地做到这一点)。

但是,可以导出函数,并且这些函数可用于在定义它们的环境中运行的Shell脚本。可以通过将其放在您的bashrc中来完成:

foo()
{
    回声“ Hello World!”
}
导出-f foo

正如Bash手册所说:“几乎所有目的,shell函数都比别名更受青睐。”


1
尽管从技术上讲这并不能解决问题,但是正如您所说,您可以简单地替换alias commandA=...commandA() { ... }then export commandA,从而获得与别名相同的行为。因此,据我所知,这几乎是别名的替代选择,在bash脚本中效果很好
Phylliida

这里的问题是,当您需要一个别名时,可以将许多引用的选项传递给该别名。例如,alias b=bash它使操作变得容易,而b -c "echo test | grep test"这在功能上是很难做到的。
Fmstrat

@Fmstrat:b () { bash "$@"; }然后b -c "echo test | grep test"
丹尼斯·威廉姆森

11
[cmd line] > bash -i [your script's file path]

i是互动和来源你bash的个人资料为您服务。


-5

我发现有时bash脚本也无法识别导出。但是,将其更改为

#!/bin/sh

为我工作。


1
不,不是……
Hafiz Temuri '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.