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

标签 linux bash sed heredoc

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

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

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

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

感谢 this answerPianosaurus

测试示例

我把它放在 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} ?> 输出命令行上为 value 给出的 name

关于linux - 在 cat << 'EOT' 之后使用 sed 仅替换生成的脚本中的一个变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46666313/

相关文章:

python - 我如何从像 git 那样的命令行程序调用文本编辑器?

bash - 使用 sed 解析鱼眼日志的问题

bash - docker上的Nginx-守护并附加到bash

regex - 使用 bash 和正则表达式获取字符串中的数字

linux - 除了使用正则表达式之外,如何在 shell 中忽略或排除备份文件 [以 ~ 结尾的文件]?

linux - 使用 sed 或 awk 替换匹配后的行

shell - 如果文件的第一行为空,则删除它

linux - 嵌入式 Linux 设备检测互联网连接的智能方法

c++ - 在 Linux 上的 C++ 中的两个线程之间使用管道的错误/意外行为

python - 缓慢的网络服务问题