在 cat 之后使用 sed << 'EOT' 来替换生成的脚本中的一个变量



我正在为ubuntu 14中的php-fpm编译、安装和部署构建一个脚本。在某一点上,我必须使用这个主脚本生成另一个文件。生成的文件是一个脚本,应该有所有变量,但有一个没有展开。

所以我从cat << 'EOT'开始,用sed解决文件生成后的问题。但我发现自己陷入了一个"逻辑"黑洞。

至于EOT引用仅扩展一个变量的问题,sed行也是如此。我直接写下了以下内容,当然,我甚至没有执行就嘲笑它。

sed -i 's/$PhpBuildVer/$PhpBuildVer' /etc/init.d/php-$PhpBuildVer-fpm

sed -i "s/$PhpBuildVer/$PhpBuildVer" /etc/init.d/php-$PhpBuildVer-fpm

两者都会失败,而我需要第一个模式是"$PhpBuildVer"本身,另一个模式是扩展变量,例如7.1.10。

如何使用sed或其他GNU Linux命令执行此替换

这是我的剧本,大部分部分都被剪掉了,因为与问题无关。

#!/bin/bash
PhpBuildVer="7.1.10"
... #removed non relevant parts of the script 
cat << 'EOT' >> /etc/init.d/php-$PhpBuildVer-fpm
#! /bin/sh
### BEGIN INIT INFO
# Provides:          php-$PhpBuildVer-fpm
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts php-$PhpBuildVer-fpm
# Description:       starts the PHP FastCGI Process Manager daemon
### END INIT INFO
php_fpm_BIN=/opt/php-$PhpBuildVer/sbin/php-fpm
php_fpm_CONF=/opt/php-$PhpBuildVer/etc/php-fpm.conf
php_fpm_PID=/opt/php-$PhpBuildVer/var/run/php-fpm.pid
php_opts="--fpm-config $php_fpm_CONF"
wait_for_pid () {
try=0
while test $try -lt 35 ; do
case "$1" in
'created')
if [ -f "$2" ] ; then
try=''
break
fi
;;
'removed')
if [ ! -f "$2" ] ; then
try=''
break
fi
;;
esac
echo -n .
try=`expr $try + 1`
sleep 1
done
}
case "$1" in
start)
echo -n "Starting php-fpm "
$php_fpm_BIN $php_opts
if [ "$?" != 0 ] ; then
echo " failed"
exit 1
fi
wait_for_pid created $php_fpm_PID
if [ -n "$try" ] ; then
echo " failed"
exit 1
else
echo " done"
fi
;;
stop)
echo -n "Gracefully shutting down php-fpm "
if [ ! -r $php_fpm_PID ] ; then
echo "warning, no pid file found - php-fpm is not running ?"
exit 1
fi
kill -QUIT `cat $php_fpm_PID`
wait_for_pid removed $php_fpm_PID
if [ -n "$try" ] ; then
echo " failed. Use force-exit"
exit 1
else
echo " done"
echo " done"
fi
;;
force-quit)
echo -n "Terminating php-fpm "
if [ ! -r $php_fpm_PID ] ; then
echo "warning, no pid file found - php-fpm is not running ?"
exit 1
fi
kill -TERM `cat $php_fpm_PID`
wait_for_pid removed $php_fpm_PID
if [ -n "$try" ] ; then
echo " failed"
exit 1
else
echo " done"
fi
;;
restart)
$0 stop
$0 start
;;
reload)
echo -n "Reload service php-fpm "
if [ ! -r $php_fpm_PID ] ; then
echo "warning, no pid file found - php-fpm is not running ?"
exit 1
fi
kill -USR2 `cat $php_fpm_PID`
echo " done"
;;
*)
echo "Usage: $0 {start|stop|force-quit|restart|reload}"
exit 1
;;
esac
EOF
#Here the variable should be substituted.
chmod 755 /etc/init.d/php-$PhpBuildVer-fpm
... #removed non relevant parts of the script 

我不能100%确定,但我认为您正在寻找的是:

sed -i 's/$PhpBuildVer/'"$PhpBuildVer"'/' /etc/init.d/php-$PhpBuildVer-fpm

实际上,您可以在bash中将两个引用的表达式放在一起。例如,echo '12'"34"'56'将输出123456。在这种情况下,第一个$PhpBuildVer位于''中,因此可以进行字面匹配,第二个位于""中,因此将进行扩展。

(但也许您应该考虑使用模板文件和php,或者(明目张胆的插件)perlpp*来构建脚本,而不是将所有文本内联到主脚本中。)

编辑顺便说一句,使用cat ... >>而不是cat ... >意味着您将附加到脚本中,除非您在代码中没有显示rm

编辑2如果$PhpBuildVer中有sed在替换文本中解释的任何字符,则可能需要对其进行转义:

repl_text="$(sed -e 's/[/&]/\&/g' <<<"$PhpBuildVer")"
sed -i 's/$PhpBuildVer/'"$repl_text"'/' /etc/init.d/php-$PhpBuildVer-fpm

感谢Pianosaurus的回答。

测试示例

我把这个放在make.sh:中

#!/bin/bash
f=42     # The variable we are going to substitute
cat <<'EOT' >"test-$f.sh"    # The script we are generating
#!/bin/sh
# Provides: test-$f.sh
echo 'Hello, world!'
EOT
echo "test-$f.sh before substitution is:"
echo "---------"
cat "test-$f.sh"
echo "---------"
sed -i 's/$f/'"$f"'/' "test-$f.sh"    # The substitution, from above
echo "test-$f.sh after substitution is:"
echo "---------"
cat "test-$f.sh"
echo "---------"

我得到的输出是:

test-42.sh before substitution is:
---------
#!/bin/sh
# Provides: test-$f.sh
echo 'Hello, world!'
---------

(注意文字$f)

test-42.sh after substitution is:
---------
#!/bin/sh
# Provides: test-42.sh
echo 'Hello, world!'
---------

(现在$f不见了,取而代之的是其值42)

perlpp示例

由于*我目前是perlpp的维护者,我也将给您举一个例子:)。在我称之为test.template的模板文件中,我放入:

#!/bin/sh
# Provides: test-<?= $S{ver} ?>.sh
echo 'Hello, world!'

这正是我想要的剧本内容,但在<?= $S{ver} ?>中,我想做替换。然后我运行

perlpp -s ver='7.1.10' test.template

(使用转义引号将其传递给perl)并获得输出:

#!/bin/sh
# Provides: test-7.1.10.sh
echo 'Hello, world!'

:)

  • perlpp的任何-s name='value'命令行参数都会创建$S{name},您可以在模板中引用它
  • <?= expr ?>打印表达式expr的值
  • 因此,<?= $S{name} ?>输出在name的命令行上给出的value

只需分解heredoc。例如

cat > file << 'EOF'
This line will not be interpolated: $FOO
EOF
cat >> file << EOF
and this line will: $FOO
EOF

如果出于某种原因,你也想使用sed,不要在之后使用,只需使用它而不是cat:

sed 's@foo@bar@g' >> file << EOF
this line's foo is changed by sed, with interpolated $variables
EOF

相关内容

  • 没有找到相关文章