我试图在脚本中设置别名,然后稍后在脚本中执行别名。我已经验证别名包含的文件路径是有效的,并且我还设置了 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
正如该问题的评论记录所反映的那样,
bash
似乎不支持 if 块或其他复合命令范围内的别名定义或 alias_expand
选项设置。 Bash 手册对此进行了解释:
有关别名的定义和使用的规则有些 令人困惑。 Bash 总是读取至少一整行输入 在执行该行上的任何命令之前。别名是 当读取命令时展开,而不是在执行命令时展开。所以, 别名定义与另一个命令出现在同一行 直到读取下一行输入才生效。命令 该行上的别名定义之后不受 新别名。执行函数时,此行为也是一个问题。 别名在读取函数定义时展开,而不是在读取函数定义时展开 函数被执行,因为函数定义本身就是一个 命令。因此,函数中定义的别名不是 直到该函数执行后才可用。 为了安全,永远 将别名定义放在单独的行上,并且不要在中使用别名 复合命令.
(强调。)注释并不直接引用 shell 选项,但是复合命令中的别名定义不适用于同一复合命令的相同逻辑也意味着它是 中
expand_aliases
选项的值当读取适用的复合命令时效果。
出现的问题是如何使用 shell 函数而不是别名来实现此目的。 这是一种方法:
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
函数来执行您想要的操作。
第三,如果您想要的只是一个直接运行并行版本或另一个版本的脚本,那么您不需要函数或别名。 只需弄清楚您要运行哪个,然后运行它,例如:
altparallel="$HOME/newnnm/parallel"
if command -v parallel >/dev/null 2>&1; then
parallel "$@"
elif [[ -x "$altparallel" ]]; then
"$altparallel" "$@"
else
exit 1
fi
别名是一个解析时间功能。它们的工作原理是在解析过程中用一个字符串替换另一个字符串。
命令在执行之前会被完全解析,这包括像
if
这样的复合命令。
这样做的效果是,对解析器的任何更改(例如设置别名)都不会在发生设置的任何可能嵌套的复合命令中生效。
例如,如果您将整个脚本包装在
{...}
中,则任何别名都不起作用,因为它现在是一个巨大的复合命令。
这也是为什么你不应该在
.bashrc
之外使用别名的另一个原因,即使如此,也要谨慎使用。使用函数。
我也遇到过同样的问题。我使用一个解决方法 - 将别名扩展存储在变量中,来自别名文件 (~/.bash_aliases)
alias_expaned=$( cat ~/.bash_aliases | awk -F"'" '/<alias name to expnad>/ {print $2}'
然后将变量使用到需要扩展的地方
您可以在 bash 脚本/命令行中使用 shopt 启用/禁用别名扩展。
$ shopt -u expand_aliases
-s
Set-u
Unset您还可以使用 unalias 删除特定别名(如果您知道的话)
$ unalias <aliasname>
请注意,当您在 BASH 脚本中使用别名时,它们不会在条件构造内扩展。 因此,虽然这个可以在脚本内部工作:
#!/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