sh:其中:第 1 行:語法錯誤:文件意外結束;sh:為“which”導入函式定義時出錯
我們正在執行: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
語法在這裡看起來是正確的。我可以說它導出了“哪個”——但我不知道為什麼。如果我知道這是做什麼的,我可以評估
unset which
.更新 2
創建了一個小的 php 腳本:
#!/usr/bin/php <?php passthru('echo hello'); ?>
這確實會產生錯誤。
我將
unset which
.bashrc 作為解決方法。這適用於 bash 和 php。今天早上我評論了unset which
來自 .bashrc 的內容。問題不再存在。我相信這個問題是由上游程式碼更改創建和解決的。謝謝@ilkkachu!
錯誤消息提示通過環境將 shell 函式導出和導入子 shell 的 Bash 特性。它讀取名稱以、 開頭的環境變數,並嘗試將它們解析為函式定義。
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 在 envvars 中使用換行符來導出函式。例如:$ which() { echo hi; } $ export -f which $ env |grep which -A1 BASH_FUNC_which%%=() { echo hi }
如果只看第一行,定義就會被破壞,就像我上面的 Perl 腳本一樣。你可能想調查一下。
至於
which
函式是從哪裡來的,看shell的初始化文件,ie/etc/bash.bashrc
等。見如何確定環境變數來自哪裡?,它們也應該適用於功能。(懶惰的第一次嘗試grep -re which /etc
:)