我运行了一个实验,看看Bash的导出函数在进程链之间使用不同的shell时是否仍然可见。
令我惊讶的是,导出的函数有时仍然可见。
我正在寻找一个解释,说明如何以及为什么Bash的特定导出函数通过不同的shell在环境中维护,而它不是POSIX标准环境变量。
不知何故,我有一个线索,导出的函数声明是作为一个字符串存储在一个(标准?)环境变量中的。但是它是如何作为一个环境变量对不兼容的shell不可见的,以及它是如何在环境中维护的?
下面是我的实验代码:
#!/usr/bin/env bash
LANG=C
# Declare function and export it
fn(){ printf 'Hello World\n';}
export -f fn
# Standard usage, call exported function within a child bash
bash -c fn
# Available shells for tests
available_shells=()
for sh in ash bash dash ksh tcsh zsh
do
if shell_path=$(command -v "$sh" 2> /dev/null)
then
available_shells+=("$shell_path")
real_shell_path=$(realpath "$shell_path")
shell_version=$(
read -r pkg < <(apt-file search "${real_shell_path#/usr}" | awk -F: '{print $1}')
dpkg -s "$pkg" | awk '/Version:/{print $2}'
)
printf 'Found: %s\tversion: %s\n' "$shell_path" "$shell_version"
fi
done
# Test transversal visibility of exported fn through different shells
for sh in "${available_shells[@]}"; do
printf "Testing %s -c 'bash -c fn':\\n" "$sh"
"$sh" -c 'bash -c fn'
printf \\n
done
字符串
我的系统上的结果显示,除了ash
和dash
之外,所有受试髋臼杯均保持导出的fn
横向可见性:
Hello World
Found: /usr/bin/ash version: 0.5.12-2ubuntu1
Found: /usr/bin/bash version: 5.2.15-2ubuntu1
Found: /usr/bin/dash version: 0.5.12-2ubuntu1
Found: /usr/bin/ksh version: 1.0.4-3
Found: /usr/bin/tcsh version: 6.24.07-1
Found: /usr/bin/zsh version: 5.9-4
Testing /usr/bin/ash -c 'bash -c fn':
bash: line 1: fn: command not found
Testing /usr/bin/bash -c 'bash -c fn':
Hello World
Testing /usr/bin/dash -c 'bash -c fn':
bash: line 1: fn: command not found
Testing /usr/bin/ksh -c 'bash -c fn':
Hello World
Testing /usr/bin/tcsh -c 'bash -c fn':
Hello World
Testing /usr/bin/zsh -c 'bash -c fn':
Hello World
型
1条答案
按热度按时间pinkon5k1#
环境实际上只能包含字符串,所以当你在bash中使用
export -f
时,它实际上只是创建了一个常规的环境变量(有一个奇怪的名字),并将其设置为函数定义的文本。例如:字符串
在bash初始化过程中,它会扫描环境中具有这样名称的变量,并将找到的任何变量转换为函数。
由于这只是一个普通的环境变量(除了它的名字),它将在各种其他程序(包括shell)中持久化,除非程序做了一些事情将它们从环境中删除。看起来dash和ash都做到了这一点(尽管我没有ash方便测试):
型
你可以在其他名字奇怪的环境变量中看到同样的效果:
型