我正在尝试在脚本中创建一个别名,如下所示:
#!/bin/bash
shopt -s expand_aliases
#Currently just using 'git' to try and get it working
#It'll be replaced with the following line when it works
#compgen -c | while read x;
echo 'git' | while read x;
do
a=`echo $x | tr '[:lower:]' '[:upper:]'`;
echo $a;
echo $x;
if [ "$a" != '' ]
then
echo 'got here';
alias $a=$x;
alias;
GIT;
fi
done
Run Code Online (Sandbox Code Playgroud)
虽然一个简单的测试脚本可以工作(testme添加到我当前shell中的别名):
#!/bin/bash
shopt -s expand_aliases
alias testme="echo It Worked"
alias
testme
Run Code Online (Sandbox Code Playgroud)
第一个脚本的输出:
GIT
git
got here
alias GIT='git'
alias grep='grep --colour=auto'
alias ls='ls --color=auto'
GIT: command not found
Run Code Online (Sandbox Code Playgroud)
GIT显示在别名中,但无法执行.我试着调用它. ./script.sh和source script.sh.我究竟做错了什么?
这可能是别名扩展时的问题.bash手册页有以下内容:
关于别名的定义和使用的规则有些令人困惑.在执行该行上的任何命令之前,Bash始终会读取至少一个完整的输入行.读取命令时会扩展别名,而不会在执行时扩展别名....
手册页中有更多信息,但是当执行复合语句(例如while循环中的列表)时,将在首次读取输入时执行扩展,而不是在执行时执行扩展.由于GIT在读取输入时未定义,因此将出现错误.
以下代码段显示了此问题:
#!/bin/bash
shopt -s expand_aliases
while read x; do
a=`echo $x | tr '[:lower:]' '[:upper:]'`
alias $a=$x
GIT # <--- this fails to execute git
done < <(echo 'git')
GIT # <--- this executes git
Run Code Online (Sandbox Code Playgroud)
一旦执行了while循环,则别名变为可用.手册页中的详细信息有点粗略,但似乎适用于函数中定义的别名注释.
另外,使用语法时要小心echo foo | while read x; do stuff; done.该while循环将在一个子shell执行,在子shell中所做的任何更改将不会持续超过该while循环.上面的示例显示了一个方法,以便while循环在当前shell中执行,但从执行的命令获取其输入.
更新:
如果上面的脚本是以原始形式编写的,它将如下所示:
#!/bin/bash
shopt -s expand_aliases
#Currently just using 'git' to try and get it working
#It'll be replaced with the following line when it works
#compgen -c | while read x;
echo 'git' | while read x; do
a=`echo $x | tr '[:lower:]' '[:upper:]'`
alias $a=$x
GIT # <--- this fails to execute git
done
GIT # <--- this also fails executes git because the alias' were set in a subshell.
Run Code Online (Sandbox Code Playgroud)
在这种情况下,别名永远不会执行.这样做的原因是管道|加注了一个新的子壳并将这些过程链接在一起.所述echo在一个过程中运行时,while read ...在其它试验,通过管连接.设置别名后,它们将在运行while循环的子shell的进程环境中设置.但是,当while循环结束时,该进程终止并丢弃其环境,以及对其环境所做的任何更改,例如添加别名.结果,第二次执行尝试GIT将失败,因为别名信息已被丢弃.
当您使用第一个脚本中显示的拓扑时,while循环将在当前脚本中运行,因此对环境所做的任何更改都会在循环结束后保持不变.
如果您执行脚本而不是获取脚本,您还会注意到此行为.如果您希望能够在这样的脚本中配置一组别名,运行脚本,在您的环境中使用它们,则会遇到同样的问题,因为您的脚本在与父shell的单独进程中运行,会创建别名,当脚本退出时随后被丢弃.
$ ./create_aliases
$ alias # <--- Ooops, no aliases defined.
Run Code Online (Sandbox Code Playgroud)
您必须像这样来源脚本,它将在当前进程中运行脚本的内容,从而修改当前环境.
$ source ./create_aliases
$ alias # <--- Yay, new aliases present.
Run Code Online (Sandbox Code Playgroud)
这就是bash将源文件等源的原因~/.bashrc,以便您在该文件中所做的更改将存在于当前环境中.