Bash脚本报': bad substitution'错误,server.xml生成后为空
问题:Cloud-Init部署Jira时server.xml生成失败(空文件+bad substitution错误)
问题现象
- 通过Cloud-Init的userdata脚本部署Jira,
dbconfig.xml文件可正常生成,但server.xml生成后为空 - 查看
cloud-init-output.log,执行生成server.xml的命令后出现: bad substitution错误,无具体行号提示 - 脚本中通过Terraform的
file函数分别传入${db_config}和${server_config}变量生成两个文件,逻辑完全一致,但仅server.xml出现问题
相关脚本片段
#!/usr/bin/env bash echo "===== Downloading EFS Util & botocore =====" yum install -y amazon-efs-utils pip3 install botocore echo "===== Downloading Jira =====" wget -O ~/jira.bin https://www.atlassian.com/software/jira/downloads/binary/atlassian-jira-software-8.22.4-x64.bin cat <<\EOF >> ~/jira.varfile app.confHome=/var/atlassian/application-data/jira app.install.service$Boolean=false portChoice=custom httpPort$Long=8080 rmiPort$Long=8443 launch.application$Boolean=false sys.adminRights$Boolean=true sys.confirmedUpdateInstallationString=false sys.installationDir=/opt/atlassian/jira sys.languageId=en EOF echo "done" echo "===== Modify Jira Permissions =====" chmod +x ~/jira.bin echo "===== Start Jira Install =====" sudo ~/jira.bin -q -varfile ~/jira.varfile echo "==== Starting Jira ====" sudo /opt/atlassian/jira/bin/startup.sh echo "===== Cleaning up Jira Files =====" rm -f ~/jira.bin rm -f ~/jira.varfile chmod 750 /opt/atlassian/jira/logs/ mkdir /var/sharedhome echo "===== Mounting EFS =====" echo "${efs_id}:/ /var/sharedhome efs _netdev,tls,iam,nofail 0 0" | tee -a /etc/fstab mount -a echo "===== Grabbing IP via SSM =====" TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") INSTANCE_IP=$(wget --header="X-aws-ec2-metadata-token:$TOKEN" -qO- http://instance-data/latest/meta-data/local-ipv4) echo "===== Configuring cluster.properties =====" echo -e "jira.node.id = node$RANDOM \njira.shared.home = /var/sharedhome \nehcache.listener.hostName = $INSTANCE_IP" | tee -a /var/atlassian/application-data/jira/cluster.properties echo "===== Adding dbconfig.xml =====" cat >/var/atlassian/application-data/jira/dbconfig.xml <<EOL ${db_config} EOL cat /var/atlassian/application-data/jira/dbconfig.xml echo "===== Adding server.xml =====" cat -v >/opt/atlassian/jira/conf/server.xml <<EOL ${server_config} EOL cat -v /opt/atlassian/jira/conf/server.xml
待写入的server.xml内容
<?xml version="1.0" encoding="utf-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <Server port="8443" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.startup.VersionLoggerListener"/> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on"/> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/> <Service name="Catalina"> <!-- ============================================================================================================== DEFAULT - Direct connector with no proxy for unproxied access to Jira. If using a http/https proxy, comment out this connector. ============================================================================================================== --> <!-- Relaxing chars because of JRASERVER-67974 --> <!-- <Connector port="8080" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^\`"<>" maxThreads="150" minSpareThreads="25" connectionTimeout="20000" enableLookups="false" maxHttpHeaderSize="8192" protocol="HTTP/1.1" useBodyEncodingForURI="true" redirectPort="8443" acceptCount="100" disableUploadTimeout="true" bindOnInit="false"/> --> <!-- ============================================================================================================== HTTP - Proxying Jira via Apache or Nginx over HTTP If you're proxying traffic to Jira over HTTP, uncomment the below connector and comment out the others. Ensure the proxyName and proxyPort are updated with the appropriate information if necessary as per the docs. See the following for more information: Apache - https://confluence.atlassian.com/x/4xQLM nginx - https://confluence.atlassian.com/x/DAFmGQ ============================================================================================================== --> <Connector port="8080" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^\`"<>" maxThreads="150" minSpareThreads="25" connectionTimeout="20000" enableLookups="false" maxHttpHeaderSize="8192" protocol="HTTP/1.1" useBodyEncodingForURI="true" redirectPort="8443" acceptCount="100" disableUploadTimeout="true" bindOnInit="false" scheme="https" proxyName="<subdomain>.<domain>.com" proxyPort="443"/> <!-- ============================================================================================================== HTTPS - Proxying Jira via Apache or Nginx over HTTPS If you're proxying traffic to Jira over HTTPS, uncomment the below connector and comment out the others. Ensure the proxyName and proxyPort are updated with the appropriate information if necessary as per the docs. See the following for more information: Apache - https://confluence.atlassian.com/x/PTT3MQ nginx - https://confluence.atlassian.com/x/DAFmGQ ============================================================================================================== --> <!-- <Connector port="8080" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^\`"<>" maxThreads="150" minSpareThreads="25" connectionTimeout="20000" enableLookups="false" maxHttpHeaderSize="8192" protocol="HTTP/1.1" useBodyEncodingForURI="true" redirectPort="8443" acceptCount="100" disableUploadTimeout="true" bindOnInit="false" secure="true" scheme="https" proxyName="<subdomain>.<domain>.com" proxyPort="443"/> --> <!-- ============================================================================================================== AJP - Proxying Jira via Apache over HTTP or HTTPS If you're proxying traffic to Jira using the AJP protocol, uncomment the following connector line See the following for more information: Apache - https://confluence.atlassian.com/x/QiJ9MQ ============================================================================================================== --> <!-- <Connector port="8009" URIEncoding="UTF-8" enableLookups="false" protocol="AJP/1.3"/> --> <Engine name="Catalina" defaultHost="localhost"> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context path="" docBase="${catalina.home}/atlassian-jira" reloadable="false" useHttpOnly="true"> <Resource name="UserTransaction" auth="Container" type="javax.transaction.UserTransaction" factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60"/> <Manager pathname=""/> <JarScanner scanManifest="false"/> <Valve className="org.apache.catalina.valves.StuckThreadDetectionValve" threshold="120" /> </Context> </Host> <Valve className="org.apache.catalina.valves.AccessLogValve" pattern="%a %{jira.request.id}r %{jira.request.username}r %t "%m %U%{sanitized.query}r %H" %s %b %D "%{sanitized.referer}r" "%{User-Agent}i" "%{jira.request.assession.id}r""/> </Engine> </Service> </Server>
错误原因
问题出在server.xml内容中的${catalina.home}:bash处理未转义的here-doc(即<<EOL)时,会自动解析所有${变量名}格式的语法。而${catalina.home}在当前Cloud-Init脚本的bash环境中未定义,触发bad substitution错误,导致整个cat写入命令失败,最终生成空的server.xml文件。
dbconfig.xml的内容中没有这类bash会解析的变量语法,所以可以正常写入。
解决方案
方案1:修改here-doc的结束标记,禁止bash解析内部变量
将生成server.xml的代码段中的<<EOL改为<<\EOL,这样bash会忽略here-doc内部的变量解析,直接将内容写入文件:
echo "===== Adding server.xml =====" cat -v >/opt/atlassian/jira/conf/server.xml <<\EOL ${server_config} EOL cat -v /opt/atlassian/jira/conf/server.xml
方案2:在Terraform中提前转义server.xml里的变量
在Terraform使用file函数读取server.xml文件时,将文件中的${catalina.home}替换为\${catalina.home},这样bash处理时不会尝试解析该变量。
验证
修改后重新执行Cloud-Init部署,server.xml会正常写入完整内容,不再出现空文件和bad substitution错误。
内容的提问来源于stack exchange,提问作者Legion_of_boom__
相关产品推荐
相关产品推荐

