简体   繁体   English

在bash脚本中设置别名

[英]Set alias within bash script

I'm trying to create an alias in a script like so: 我正在尝试在脚本中创建一个别名,如下所示:

#!/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

While a simple test script works ( testme is added to the aliases in my current shell): 虽然一个简单的测试脚本可以工作( testme被添加到我当前shell中的别名):

#!/bin/bash
shopt -s expand_aliases
alias testme="echo It Worked"
alias
testme

Output from first script: 第一个脚本的输出:

GIT
git
got here
alias GIT='git'
alias grep='grep --colour=auto'
alias ls='ls --color=auto'
GIT: command not found

GIT shows up in the aliases, but can't be executed. GIT显示在别名中,但无法执行。 I've tried calling it with . ./script.sh 我试过用它来试试. ./script.sh . ./script.sh and source script.sh . . ./script.shsource script.sh What am I doing wrong? 我究竟做错了什么?

It's likely a problem of when the alias is expanded. 这可能是别名扩展的问题。 The bash man page has the following to say: bash手册页有以下内容:

The rules concerning the definition and use of aliases are somewhat confusing. 关于别名的定义和使用的规则有些令人困惑。 Bash always reads at least one complete line of input before executing any of the commands on that line. 在执行该行上的任何命令之前,Bash始终会读取至少一个完整的输入行。 Aliases are expanded when a command is read, not when it is executed. 读取命令时会扩展别名,而不会在执行时扩展别名。 ... ...

There's more info in the man page, but when executing a compound statement such as the list within your while loop, the expansion will occur when when the input is first read, not when executed. 手册页中有更多信息,但在执行复合语句(例如while循环中的列表) while ,将在首次读取输入时执行扩展,而不是在执行时进行扩展。 Since GIT is not defined when the input is read, there will be an error. 由于在读取输入时未定义GIT ,因此将出现错误。

The following snippet shows the issue: 以下代码段显示了此问题:

#!/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

Once the while loop has executed, then the alias becomes available. 一旦执行了while循环,则别名变为可用。 Details in the man page are a bit sketchy, but it appears as though the comments for aliases defined in functions would apply. 手册页中的详细信息有点粗略,但似乎适用于函数中定义的别名注释。

Also, be careful when using syntax such as echo foo | while read x; do stuff; done 另外,使用echo foo | while read x; do stuff; done等语法时要小心 echo foo | while read x; do stuff; done echo foo | while read x; do stuff; done . echo foo | while read x; do stuff; done The while loop will execute in a subshell, any changes made in the subshell will not persist beyond the while loop. while循环将在子shell中执行,子shell中所做的任何更改都不会超出while循环。 The example above shows a method so that the while loop executes in the current shell, but takes its input from a command which is executed. 上面的示例显示了一个方法,以便while循环在当前shell中执行,但从执行的命令获取其输入。

Update: 更新:

If the above script were written in its original form it would look like this: 如果上面的脚本是以原始形式编写的,它将如下所示:

#!/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.

In this case, the alias is never executed. 在这种情况下,别名永远不会执行。 The reason for this is that the pipe | 原因是管道| stars a new subshell and links the processes together. 为一个新的子shell加注星标并将这些过程链接在一起 The echo runs in one process, the while read ... runs in the other, linked by a pipe. echo在一个进程中运行, while read ...在另一个进程中运行,由管道链接。 When the aliases are set, they are set in the environment of the process of the subshell running the while loop. 设置别名后,它们将在运行while循环的子shell的进程环境中设置。 However, when the while loop has finished, that process terminates and its environment is discarded, along with any changes made to its environment such as the addition of aliases. 但是,当while循环结束时,该进程将终止并丢弃其环境,以及对其环境所做的任何更改,例如添加别名。 As a result, the second attempt to execute GIT will fail as the alias information has been discarded. 结果,执行GIT的第二次尝试将失败,因为别名信息已被丢弃。

When you use the topology shown in the first script, the while loops runs in the current script, so any changes made to the environment persist past the end of the loop. 当您使用第一个脚本中显示的拓扑时, while循环在当前脚本中运行,因此对环境所做的任何更改都会在循环结束后保持不变。

You will also notice this behaviour if you execute your script, rather than sourcing it. 如果您执行脚本而不是获取脚本,您还会注意到此行为。 If you expect to be able to configure a set of aliases in a script like this, run the script, have them available in your environment, you have the same problem because your script runs in a separate process to the parent shell, creates the aliases, which are subsequently discarded when the script exits. 如果您希望能够在这样的脚本中配置一组别名,运行脚本,让它们在您的环境中可用,您遇到同样的问题,因为您的脚本在一个单独的进程中运行到父shell,创建别名,当脚本退出时随后被丢弃。

$ ./create_aliases
$ alias  # <--- Ooops, no aliases defined.

You'd have to source your script like this, which will run the contents of the script in the current process, thus modifying the current environment. 您必须像这样来源脚本,它将在当前进程中运行脚本的内容,从而修改当前环境。

$ source ./create_aliases
$ alias # <--- Yay, new aliases present.

This is why bash will source files such as ~/.bashrc , so that changes you make in that file will exist in the current environment. 这就是为什么bash将提供诸如~/.bashrc文件,以便您在该文件中所做的更改将存在于当前环境中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM