为什么 bash 检查我这里文档文本的语法?

为什么 bash 检查我这里文档文本的语法?

我的文件中有以下代码块:

175 MY_IP=`ifconfig eno1 | grep netmask | tr -s ' ' | cut -d " " -f 3`  
176 echo ""  > /home/hadoop/.ssh/config  
177 cat > /home/hadoop/.ssh/config  <<EOF  
178 Host `echo $MY_IP | sed 's/.[0-9][0-9]*$//g'`.* 0.0.0.0 master   worker*  
179    StrictHostKeyChecking no  
180    UserKnownHostsFile=/dev/null  
181 EOF  

我希望将第 178 行到第 181 行写入文件,但我得到以下错误输出:

/script.sh: line 178: unexpected EOF while looking for matching `''
/script.sh: line 184: syntax error: unexpected end of file

为什么它不只是复制该文本而不检查其语法?

更新:我的代码和错误消息现在的样子:

175 MY_IP=`ifconfig eno1 | grep netmask | tr -s ' ' | cut -d " " -f 3`  
176 echo ""  > /home/hadoop/.ssh/config  
177 cat > /home/hadoop/.ssh/config  <<EOF  
178 Host `echo $MY_IP | sed "s/.[0-9][0-9]*$//g"`.* 0.0.0.0 master worker*  
179    StrictHostKeyChecking no  
180    UserKnownHostsFile=/dev/null  
181 EOF  
182   
183 chown -R hadoop:hadoop /home/hadoop  

/script.sh:第 175 行:查找匹配的“”时出现意外的 EOF
/script.sh:第 184 行:语法错误:意外的文件结尾

已解决:检查我的代码后,我发现第一行中缺少单引号。将其与另一个配对解决了该问题。

答案1

shell 将`echo ...`在此处的文档中执行不同类型的扩展(包括像您的命令替换,还有变量和算术扩展)除非分隔符被引用

比较:

cat <<EOF
$$ $((2 + 3)) $(hostname) `date`
EOF
4502 5 fazq Mon Mar 11 23:03:27 EET 2019

对比:

cat <<'EOF'
$$ $((2 + 3)) $(hostname) `date`
EOF
$$ $((2 + 3)) $(hostname) `date`

在最后一种情况下,双引号或单引号都可以。

答案2

man bash

这里的文件
这种类型的重定向指示 shell 从当前源读取输入,直到仅包含分隔符的行(没有尾随空格)被看到。到该点读取的所有行都将用作命令的标准输入(或文件描述符 n,如果指定了 n)。

正如问题中当前发布的那样,您的 EOF 行包含尾随空格。删除它们。

答案3

我们这里没有完整的脚本,但请注意,当您将此处文档中的引号从单引号更改为双引号时,“查找匹配 [单引号] 时出现意外的 EOF” 上的行号如何从 178 更改为 175引号。

这向我暗示,实际的问题(未完成的引用)位于您发布的片段之前的某个位置。

例如,在下面的脚本中实际的错误显然在第一行,但从 shell 的角度来看,从那里开始的带引号的字符串一直持续到下一个引号,依此类推,未配对的字符串是后面的字符串bar(注意语法突出显示如何明显表明第二个echo被引用,foo并且bar没有被引用):

$ cat quote.sh
echo 'error here

echo 'foo' 'bar'
$ bash quote.sh
quote.sh: line 3: unexpected EOF while looking for matching `''
quote.sh: line 4: syntax error: unexpected end of file

将第二个echo命令更改为echo "foo" "bar"将在第 1 行显示错误,因为这将是最终单引号字符串开始的行。

您需要更仔细地查看整个脚本。或者将其转储到 shellcheck.net,它会注意到类似的情况。

相关内容