什么可能阻止我的别名在shell脚本中扩展

时间:2017-03-09 15:25:32

标签: bash scripting

我正在尝试在脚本中设置别名,然后在脚本中执行别名。我已经验证了别名包含的文件路径是有效的,我还设置了shell脚本来扩展别名,但脚本仍然拒绝使用别名。我在这里做错了什么?

脚本:

#set location of parallel script and replace ~ with $HOME if necessary
parallellocation="~/newnnm/parallel"
parallellocation="${parallellocation/#\~/$HOME}"
#If the parallellocation variable is set and a parallel command is not currently available, 
#proceed with setting an alias that points to the parallellocation variable
if [ -r "$parallellocation" ] && ! command -v parallel &>/dev/null; then
        shopt -s expand_aliases
        alias parallel="$parallellocation"
        parallel
fi

示例输出:

./processlocations_new2.sh
./processlocations_new2.sh: line 98: parallel: command not found

3 个答案:

答案 0 :(得分:3)

正如问题的评论记录中所反映的那样,bash似乎不会在if块或其他复合命令的范围内遵守别名定义或设置alias_expand选项。 Bash Manual解释了这一点:

  

关于别名的定义和使用的规则有所不同   混乱。 Bash总是读取至少一个完整的输入行   在执行该行上的任何命令之前。别名是   读取命令时扩展,而不是执行时扩展。因此,    与另一个命令出现在同一行的别名定义   在读取下一行输入 之前不会生效。命令   跟随该行的别名定义不受该行的影响   新别名。执行函数时,此行为也是一个问题。    在读取函数定义时扩展别名,而不是在   函数执行,因为函数定义本身就是一个   命令 即可。因此,函数中定义的别名不是   直到该功能执行后才可用。 永远保持安全   将别名定义放在单独的行上,不要使用别名   复合命令

(强调补充。)注释不直接引用shell选项,但是复合命令中别名定义不适用于同一复合命令的相同逻辑也意味着它是{{1读取适用的复合命令时生效的选项。

出现的问题是如何为此目的使用shell函数而不是别名。这是一种方式:

expand_aliases

您从环境设置脚本中获取该内容,以获得定义的altparallel="$HOME/newnnm/parallel" parallellocation= if command -v parallel >/dev/null 2>&1; then parallellocation="command parallel" elif [[ -x "$altparallel" ]]; then parallellocation="$altparallel" fi # Runs parallel with the given arguments. Uses the 'parallel' command # found in the path if there is one, or a local one designated by # $altparallel if that exists and is executable. Exit status is that of # 'parallel', or 1 if no 'parallel' command is available. parallel() { [[ -z "$parallellocation" ]] && return 1 # expansion of $parallellocation is intentionally unquoted $parallellocation "$@" } 函数,以满足您的需求。

第三方面,如果你想要的只是一个运行一个版本的parallel或另一个版本的脚本,那么你就不需要函数或别名。只需弄清楚你想要运行哪个并运行它,例如:

parallel

答案 1 :(得分:1)

别名是解析时间功能。它们通过在解析期间将一个字符串替换为另一个字符串来工作。

命令在执行之前会被完全解析,这包括if之类的复合命令。

这样做的结果是对解析器的任何更改(如设置别名)都不会在设置发生的任何可能嵌套的复合命令中生效。

例如,如果将整个脚本包装在{...}中,则没有别名可以工作,因为它现在是一个巨大的复合命令。

这是你永远不应该在.bashrc之外使用别名的另一个原因,即使这样,也只是谨慎使用。使用功能。

答案 2 :(得分:-2)

您可以在bash脚本/命令行中使用 shopt 启用/禁用别名扩展。

$ shopt -u expand_aliases
  • -s S et
  • -u U nset

您还可以使用 unalias 删除特定别名(如果您了解它们)

$ unalias <aliasname>

请注意,当您在BASH srcipts中使用别名时,它们不会在条件结构中扩展。 因此,虽然这个可以在脚本内部工作:

#!/bin/bash
shopt -e expand_aliases
alias list1='ls -lhS'
list1

这个不会:

#!/bin/bash
shopt -e expand_aliases
alias list2='ls -lah'
if [ 1 ]; then
  list2
fi

正如其他人在评论部分中指出的那样,使用函数,或使用 eval 来执行$parallellocation中存储的命令字符串:

eval $parallellocation