bash while 循环中设置的别名不会持续存在

bash aliases set in while loop not persisting

好的,我写了一个 shell 脚本来读取格式为:

的文件

快捷方式 1 /path/to/directory1
捷径2 /path/to/directory2

它应该读取文件并构建别名,以便在映射目录中键入 shortcut1 cd 。问题是,循环中设置的任何别名都不会在脚本之外持续存在。

首先我只尝试 运行 脚本。

. ./build_shortcuts.sh "~/.shortcuts"

文件 ~/.shortcuts 包含的位置

dl ~/Downloads
music /music
dtop ~/Desktop

这没有用。然后我尝试在循环外设置一些别名。比如alias hello='world';别名 world='hellob'。我重新运行脚本,键入 alias 以获取别名列表,它确实包含 hello 和 world 作为别名,但没有在循环中设置的任何别名。

然后我想也许循环根本没有设置它们,所以我在脚本中添加了别名作为最后一个命令,所以它会在最后打印出别名;在这种情况下,它确实包含了别名,但它们仍然没有在我的会话中持续存在。

build_shortcuts.sh

script="$(cat $@ | sed -r -e 's/#[A-Za-z0-9 ]*$//' -e '/^\s+/s/^\s+//' -e '/^\s*$/d' -)"
# strip comments, entry level indentation & empty lines (in that order) from filestream

echo "${script}" | while read shortcut; do
    cut=$(echo  "${shortcut}" | awk '{         print  }')
    dest=$(echo "${shortcut}" | awk '{ =nil; print [=11=] }')
    dest="${dest:1}" # trim leading whitespace character

    alias "${cut}" &>/dev/null

    if [ $? = 0 ]; then
        echo "Warning: shortcut \"${cut}\" already exists" >&2
        continue # by default, skip overwriting shortcuts
    fi

    echo alias ${cut}="'cd ${dest}'"
    alias "${cut}"="'cd ${dest}'"
done

我希望脚本内循环中设置的别名存在于脚本之外。目前他们没有。

我 运行 在 "GNU bash, version 5.0.7(1)-release (x86_64-pc-linux-gnu)" 上 linux。

来自the Bash manual page(关于管道的部分):

Each command in a pipeline is executed as a separate process (i.e., in a subshell)

由于循环是作为管道的一部分完成的,因此它将是一个子 shell,并且您在子 shell 中执行的别名命令只会为该子 shell 设置。

一种可能的 work-around 是将别名保存到列表中,然后在第二个循环中执行实际的 alias 命令,该循环不是管道或子外壳的一部分.

你的脚本可以精简一点:不需要调用那么多外部工具。

while read -r cut dest; do
    if alias "${cut}" &>/dev/null; then
        echo "Warning: shortcut \"${cut}\" already exists" >&2
    else        
        echo alias ${cut}="'cd ${dest}'"
        alias "${cut}"="'cd ${dest}'"
    fi
done < <(
    sed -E -e 's/#[A-Za-z0-9 ]*$//' -e '/^\s+/s/^\s+//' -e '/^\s*$/d' "$@"
)

在 "done" 之后,我正在重定向来自进程替换的输入:这避免了子外壳中来自 运行 的 "while read" 循环。