在 cat << 'EOT' 之后使用 sed 仅替换生成的脚本中的一个变量
Using sed after cat << 'EOT' to substitute just one variable inside the generated script
我正在为 php-fpm 编译、安装和部署构建一个脚本 ubuntu 14. 有一次,我必须使用这个主脚本生成另一个文件。生成的文件是一个脚本,应该包含所有变量,但没有展开。
所以我从 cat << 'EOT'
开始,打算用 sed
解决文件生成后的问题。但我发现自己陷入了 "logic" 黑洞。
至于 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 "" in
'created')
if [ -f "" ] ; then
try=''
break
fi
;;
'removed')
if [ ! -f "" ] ; then
try=''
break
fi
;;
esac
echo -n .
try=`expr $try + 1`
sleep 1
done
}
case "" 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)
[=13=] stop
[=13=] 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: [=13=] {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* 构建脚本,而不是将所有文本内联到主脚本中。 ;) )
Edit 顺便说一句,使用 cat ... >>
而不是 cat ... >
意味着您将附加到脚本,除非您已经 rm
ed它在您未显示的代码中的某处。
编辑 2 如果 $PhpBuildVer
中有任何 sed
在替换文本中解释的字符,您可能需要将其转义:
repl_text="$(sed -e 's/[\/&]/\&/g' <<<"$PhpBuildVer")"
sed -i 's/$PhpBuildVer/'"$repl_text"'/' /etc/init.d/php-$PhpBuildVer-fpm
感谢this answer by 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
我正在为 php-fpm 编译、安装和部署构建一个脚本 ubuntu 14. 有一次,我必须使用这个主脚本生成另一个文件。生成的文件是一个脚本,应该包含所有变量,但没有展开。
所以我从 cat << 'EOT'
开始,打算用 sed
解决文件生成后的问题。但我发现自己陷入了 "logic" 黑洞。
至于 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 "" in
'created')
if [ -f "" ] ; then
try=''
break
fi
;;
'removed')
if [ ! -f "" ] ; then
try=''
break
fi
;;
esac
echo -n .
try=`expr $try + 1`
sleep 1
done
}
case "" 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)
[=13=] stop
[=13=] 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: [=13=] {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* 构建脚本,而不是将所有文本内联到主脚本中。 ;) )
Edit 顺便说一句,使用 cat ... >>
而不是 cat ... >
意味着您将附加到脚本,除非您已经 rm
ed它在您未显示的代码中的某处。
编辑 2 如果 $PhpBuildVer
中有任何 sed
在替换文本中解释的字符,您可能需要将其转义:
repl_text="$(sed -e 's/[\/&]/\&/g' <<<"$PhpBuildVer")"
sed -i 's/$PhpBuildVer/'"$repl_text"'/' /etc/init.d/php-$PhpBuildVer-fpm
感谢this answer by 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