我们正在运行:Red Hat Enterprise Linux 版本 8.5 (Ootpa)。我们允许服务器使用“yum -y update”每周更新一次。最近,我们在执行 shell 命令时开始收到以下错误:
- sh: 其中:第 1 行:语法错误:意外的文件结尾
- sh:导入“which”的函数定义时出错
我不知道我们所做的任何更改可能会导致此错误 - 这就是为什么我指向 yum 系统更新。我们的大部分代码都是用 php 编写的,其中我们使用 passthru() 来运行 shell 命令。当我们很少编写 shell 脚本时,我们通常使用 bash。
在运行使用 passthru() 的 php 脚本之前,我能够使用“unset which”来防止这些错误。我们从许多脚本运行许多 shell 命令。更新这些脚本中的每一个都不是有效的解决方案——不仅耗时而且可能会引入缺陷。
有趣的是,以下代码不会导致错误:
#!/bin/sh
echo hello
有没有办法在系统或用户级别“取消设置”一次,以便每次运行 shell 时都会执行它?也许有一个我可以更改的外壳配置文件或类似的东西。
更新1
我在 /etc/profile.d/which2.sh 中发现以下内容
# shellcheck shell=sh
# Initialization script for bash, sh, mksh and ksh
which_declare="declare -f"
which_opt="-f"
which_shell="$(cat /proc/$$/comm)"
if [ "$which_shell" = "ksh" ] || [ "$which_shell" = "mksh" ] || [ "$which_shell" = "zsh" ] ; then
which_declare="typeset -f"
which_opt=""
fi
which ()
{
(alias; eval ${which_declare}) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot "$@"
}
export which_declare
export ${which_opt} which
这里的语法看起来是正确的。我可以看出它导出“which”——但我不确定为什么。如果我知道这是做什么的,我就可以评估 的风险unset which
。
更新2
创建了一个小的 php 脚本:
#!/usr/bin/php
<?php
passthru('echo hello');
?>
这确实会产生错误。
答案1
该错误消息暗示了 Bash 功能通过环境将 shell 函数导出和导入到子 shell。它读取名称类似于 的环境变量,其值以 开头,并尝试将它们解析为函数定义。BASH_FUNC_funcname%%
() {
该错误表明定义有错误,您可以通过例如缺少结束语来得到该错误}
。这里,() { echo hi;
当 Bash 看到它时,环境变量将包含该字符串:
$ perl -e '$ENV{"BASH_FUNC_which%%"} = "() { echo hi;"; exec("/bin/bash")'
bash: which: line 1: syntax error: unexpected end of file
bash: error importing function definition for `which'
unset which
会取消定义该函数,因此它不会被导出,但这并不能解释为什么当从 PHP 启动 shell 时定义会被破坏。我不确定 PHP 或您的 PHP 程序对环境变量做了什么,但可能的原因是 Bash 在导出函数的环境变量中使用换行符。例如:
$ which() { echo hi; }
$ export -f which
$ env |grep which -A1
BASH_FUNC_which%%=() { echo hi
}
如果只看第一行,定义就会被破坏,就像我上面的 Perl 脚本一样。你可能想调查一下。
至于该which
函数来自哪里,请查看shell的初始化文件,即/etc/bash.bashrc
等。请参阅中的想法如何确定环境变量来自哪里?,它们也应该适用于函数。 (懒惰的第一次尝试grep -re which /etc
:)
答案2
我将其放在unset which
.bashrc 中作为解决方法。这对 bash 和 php 都有效。今天早上我评论了unset which
.bashrc。该问题不再存在。我相信这个问题是由上游代码更改造成并解决的。谢谢@ilkkachu!