如果我理解你在做什么,问题是script 正在启动一个新的 shell(作为子进程),并且它没有旧的(父进程)shell 的变量。你能在script 开始after 定义变量,所以它是在正确的shell 中定义的吗?
另一种可能的解决方案是export变量,它将它从shell变量转换为环境变量,子进程将继承它的副本。请注意,根据您使用的 shell,您可能需要将分配的值用双引号引起来,以避免出现分词问题:
export filename="$(ls /home/*.txt | xargs -n1 -I{} basename "{}" | head -3)"
顺便说一句,这种处理文件名列表的方式会遇到带有空格或其他一些 shell 元字符的名称的问题。处理文件名列表的正确方法是将它们存储为数组,但不幸的是无法导出数组。
[编辑:] 带有空格和/或其他奇怪字符的文件名的问题在于 1)ls 输出文件名的方式模棱两可且不一致,以及 2)不带引号的变量上的 shell“分词”可以解析文件名......不幸......方式。举个极端的例子,假设你有一个名为 /home/this * that.txt 的文件——如果它在一个变量中,并且你使用的变量没有双引号,它将把 /home/this 和 that.txt 视为完全独立的东西,它还将* 扩展为当前目录中的文件名列表。请参阅this question from yesterday,了解此类事情真实发生的众多示例之一。
为了安全地处理带有奇怪字符的文件名,基本规则是获取使用原始 shell 通配符(不是 ls!)或 find 与 -exec 或 -print0 的文件列表,始终存储数组中的文件名(不是普通变量),并用双引号将所有变量(/array)引用。见BashFAQ #20: "How can I find and safely handle file names containing newlines, spaces or both?"
在这种情况下,您只需要使用通配符表达式来制作路径数组,然后使用 shell 的内置字符串操作来删除路径前缀:
filepaths=( /home/*.txt ) # Create array of matching files
filenames=( "${filepaths[@]##*/}" ) # Remove path prefixes
然后您可以使用"${filenames[@]:0:3}" 从数组中获取前三个名称。您可以仅使用前三个文件创建一个新数组,也可以直接在循环中使用它:
first3files=( "${filenames[@]:0:3}" ) # ...or...
for f in "${filenames[@]:0:3}"; do
echo "$f" # Always double-quote variable references!
done
请注意,bash 不允许堆叠大多数数组/变量修饰符,因此获取路径数组、去除前缀并仅选择前几个,必须分三个单独的步骤完成。