【问题标题】:Using a Perl one-liner in a shell script在 shell 脚本中使用 Perl 单行
【发布时间】:2015-08-20 09:24:47
【问题描述】:

这让我沮丧了好几个小时。我围绕 Perl 单行编写了一个简单的包装器来更新一些 DNS 区域文件中的序列。

我觉得有必要补充一下:- 不要提供其他方法来做到这一点,好吗?这是关于为什么这不起作用,而不是关于如何通过其他方式达到结果。

这是我的简单脚本

#!/bin/bash
#loop through the supplied files updating the timestamp (serial)
SERIAL=`date +%Y%m%d%H%M`;
for name in $@
do
saCMD="'s/^(\W*)\d*.*;\W*serial/\${1}$SERIAL ; serial/g'"
#echo the command 
echo "perl -pi -e "$saCMD" $name"
#execute the command
`perl -pi -e $saCMD $name`
done
  

我尝试了多种不同的方法,但都以静默方式或消息失败

在 -e 第 1 行的 EOF 之前的任何地方都找不到字符串终止符“'”..

如果我执行回显的命令,它会正常工作

我使用的是 Debian 7 系统

谁能指出我为什么没有像我期望的那样执行?

编辑:

一些示例数据

$TTL 300
domain.org. IN SOA     ns1.domain.com. admin.domain.org. (
                2014090914      ; serial, todays date+todays
                7200            ; refresh, seconds
                7200            ; retry, seconds
                2419200         ; expire, seconds
                3600 )          ; minimum, seconds        

感兴趣的线路是2014090914 ; serial, todays date+todays

【问题讨论】:

  • 出于兴趣 - 如果省略反引号,它会起作用吗?我问的原因 - 反引号会产生一个子shell,我认为它可能会打开另一层引号。
  • 反引号没有明显区别。
  • 奇数。因为像这样内联反引号应该导致执行该 perl 命令的输出。
  • 它不只是将输出返回给脚本吗?就像我如何格式化时间戳一样?由于 perl 没有返回错误,所以没有输出。同样的命令在 Centos 上完美运行。 (虽然我最近没有测试过)

标签: bash perl shell debian


【解决方案1】:

至少存在引用问题。您将单引号作为saCMD="'s...'" 的一部分。它们不会被 shell 删除,而是传递给 perl,正如您在 echo 输出中看到的那样。

另外,

#execute the command
`perl -pi -e $saCMD $name`

可能有无用的反引号。或者您是否还想运行 perl 脚本输出的命令?要调试 shell 脚本,请将 set -x 放在开头。

这在这里有效:

#!/bin/bash
SERIAL=$(date +%Y%m%d%H%M)
for name in "$@"; do
  saCMD="s/^(\W*)\d*.*;\W*serial/\${1}$SERIAL ; serial/"
  perl -pi -e "$saCMD" "$name"
done

并将您的示例数据转换为

$TTL 300
domain.org. IN SOA     ns1.domain.com. admin.domain.org. (
                201508201330 ; serial, todays date+todays
                7200            ; refresh, seconds
                7200            ; retry, seconds
                2419200         ; expire, seconds
                3600 )          ; minimum, seconds

【讨论】:

  • 我知道反引号大多是多余的。我想知道它是否改变了命令的解释方式。单引号是为了传递给 perl 正在执行的“脚本”perl 应用程序。如果没有单引号,它将被视为多个变量
  • 感谢 set -x 的提示。它输出命令。如果我直接在命令行上运行它确实有效。但不是来自 shell 脚本
  • 好的,我现在知道发生了什么。由于它被有效地引用了两次,Perl 不承认它是一个正则表达式。耶。
【解决方案2】:

正确的引用应该会有所帮助。你没有显示输入数据,所以我无法测试:

saCMD="s/^(\W*)\d*.*;\W*serial/\${1}$SERIAL ; serial/g" # No inner quotes.
perl -pi -e "$saCMD" "$name"

另外,/g 似乎毫无意义,因为正则表达式只匹配字符串的开头 (^)。

【讨论】:

  • 我尝试了多种不同的正则表达式,最初它与开头不匹配。令人困惑的是,如果我回显命令并直接从命令行运行它,它会完全按照它应该的方式工作。
  • @DeveloperChris 那是因为在剪切/粘贴回显命令时,您将它第二次传递给 shell,shell 再次执行引号删除并在调用 perl 之前去除单引号。这就像echo "''"echo '' 的区别。
  • @Jens 是的,它确实删除了单引号,但只有在将字符串分配给参数之后,否则字符串将被分解为许多参数。无论脚本是从 shell 脚本中调用还是从命令行调用,它仍然需要引号。两种方法我都试过了。
最近更新 更多