【问题标题】:Perl command in a bash script is not interpreting command (it is literally substituting it)bash 脚本中的 Perl 命令不是解释命令(实际上是替换它)
【发布时间】:2019-06-12 07:26:56
【问题描述】:

我的 bash 脚本使用 perl 命令将文件中的变量替换为另一个文件的内容。我认为很标准,但我在这里真的很挣扎。

#/bin/bash

display_usage() {
        echo -e "\nUsage: This script must be run with an environment parameter (file in directory env/)."
        echo -e "Example: ./configureEnv <env parameter>\n"
        }

# If no env argument supplied, display usage.
if [  $# -eq 0 ]; then
        display_usage
        exit 1
fi

# Replace the placeholder of FIREBASE_ENV in index.html with the Firebase env settings.
perl -pi -e 's/%FIREBASE_ENV%/`cat testEnvConfig`/g;' index.html

if [ $? -eq 0 ]; then
   echo "Updated Firebase settings based on environment file: $1"
   exit 0
else
    echo "[Error] Environment settings configuration failed. Please check parameters are correct."
    exit 1
fi

如你所见,关键是:

perl -pi -e 's/%FIREBASE_ENV%/`cat testEnvConfig`/g;' index.html

它应该将 %FIREBASE_ENV% 的占位符字符串替换为文件的内容,而是将 %FIREBASE_ENV% 替换为 `cat testEnvConfig`

【问题讨论】:

    标签: regex linux bash perl


    【解决方案1】:

    替换中的替换会插入双引号等变量,但它不会解释反引号。您需要指定 /e 修饰符以将替换评估为代码。

    s/%FIREBASE_ENV%/`cat testEnvConfig`/ge
    

    不过,您无需为此付出任何代价。 Perl 可以读取文件并将其内容存储在变量中:

    my $config = do { local( @ARGV, $/ ) = 'testEnvConfig'; <> };
    # ...
    s/%FIREBASE_ENV%/$config/g;
    

    【讨论】:

    • 以前从未见过local @ARGV=filename --- 感谢您向我展示!
    【解决方案2】:

    使用(非常有用的)Perl 模块Path::Tiny 读取文件只需一条语句,我们就有

    perl -MPath::Tiny -i.bak -pe'
        BEGIN { $f = path("testEnvConfig")->slurp; chomp $f }; 
        s/%FIREBASE_ENV%/$f/g
    ' index.html
    

    为了您在测试时的安全,我添加了一个备份 .bak,并将代码拆分为多行以提高可读性。

    我从文件中删除了最后一个换行符。如果你真的想要它删除 chomp $f


    解释了为什么您的诚实尝试不起作用,因为您需要使用 /e 将替换部件评估为代码。然而,一旦你这样做了,看看情况:

    • 从 bash 脚本调用 Perl 程序(单线)

    • 输出到系统(至少是一个系统调用,也许是另一个 shell!)

    • 另一个程序在哪里运行 (cat)

    • 将文件内容发送回 Perl,然后由 Perl 执行。

    嗯。最好用 Perl 读取那个文件,不是吗?

    【讨论】:

      【解决方案3】:

      默认情况下,替换的右侧 (s///) 的作用类似于双引号字符串。 "`cat whatever`" 在字符串中没有做任何特别的事情;它不运行任何命令。

      您需要使用/e 标志:

      s/%FIREBASE_ENV%/`cat testEnvConfig`/eg
      

      这告诉 Perl 右手边将被计算为一个代码块,而不是一个字符串。

      或者,您可以通过在 Perl 中读取文件来避免对cat 进行攻击:

      perl -pi -e 'BEGIN { my $file = "testEnvConfig"; open my $fh, "<", $file or die "$file: $!\n"; local $/; $config = readline $fh } s/%FIREBASE_ENV%/$config/g'
      

      这也避免了每次出现%FIREBASE_ENV%时都必须重新读取文件。

      【讨论】:

      • 这是完美的答案。我没有使用 /e 标志(仅 /g)。我对 Perl 和 SED 感到困惑。谢谢
      猜你喜欢
      • 1970-01-01
      • 2010-11-29
      • 1970-01-01
      • 1970-01-01
      • 2012-06-10
      • 1970-01-01
      • 2013-12-25
      • 2014-08-23
      • 1970-01-01
      相关资源
      最近更新 更多