【问题标题】:Shell script: Replace matching text with output of programShell脚本:用程序的输出替换匹配的文本
【发布时间】:2010-11-27 01:25:32
【问题描述】:

我想用在这些字符串上运行的程序的输出替换文本流中的特定字符串。例如,将任何出现的“#filename#”替换为identify filename的输出

有什么简单的方法吗?

【问题讨论】:

  • 您需要动态更改替换字符串还是identify filename静态的输出(针对该流)?
  • 我想动态改变输出:我无法预测我会得到什么文件名,直到我看到它们。

标签: perl shell command-line


【解决方案1】:

假设 'identify filename' 本身就是一个命令,那么我认为您需要为此使用 Perl。以最好的 Perl 神秘风格:

while (<>)
{
     s/#(\w+)#/my $x = qx%identify $1%; chomp $x; $x/e;
     print;
}

这会将一行输入('&lt;&gt;')读入隐式变量'$_';下一行对隐式变量应用替换操作 - 稍后会详细介绍 - 然后 'print' 打印隐式变量。

对于替换操作“s///”,第一部分查找哈希“#”、一系列一个或多个“单词”字符 - 字母数字或下划线 - 以及另一个哈希,使识别的文件名可用作为'$1'。第二部分是替换字符串。第三个斜线之后是修饰符“e”,意思是“将替换作为 Perl 的位执行”。 Perl的相关位是:

my $x = qx%identify $1%; chomp $x; $x

如果哈希标记之间的字符串是“文件名”,则第一部分执行命令“identify filename”,将输出、换行符和所有内容保存在局部变量 $x 中。 'chomp' 操作删除换行符;最后的 '$x' 产生一个值 - 由 'identify' 命令输出的字符串。 (令我惊讶的是,Perl 不允许使用更简单的外观:s/#(\w+)#/chomp qx%identify $1%/e;错误是 'Can't modify quoted execution (``, qx) in chomp at xx.pl line 3, near "qx%identify $1%)"'。)

考虑“识别”命令:

echo "identified file $1 as $PWD/$1"

现在考虑输入行:

abc#def#ghi

输出是:

abcidentified file def as /Users/jleffler/tmp/soq/defghi

(在运行命令时,/Users/jleffler/tmp/soq 恰好是我的当前目录)。

相当不神秘:

while (my $line = <>)
{
    if ($line =~ m/#(\w+)#/)
    {
        my $identity = qx{identify $1};
        chomp $identity;
        $line =~ s/#\w+#/$identity/;
    }
    print $line;
}

当然没有那么紧凑,但解释非常相似。

请注意,初始版本可能不是最紧凑的形式。考虑这个版本:

perl -p -e 's/#(\w+)#/my $x = qx%identify $1%; chomp $x; $x/e'

“-p”选项将脚本(“-e”的参数)置于读取、执行、打印循环 (REPL) 中。

这是 Perl 的奇迹之一 - TMTOWTDI(发音为 'tim-toady') - 有不止一种方法可以做到这一点。

【讨论】:

  • 正是我想要的。非常感谢。不过,让我补充一下, (\w+) 不是文件名的最佳匹配:它不接受句点。
  • @nikitakit:毫无疑问是正确的——但这就是你知道需要应用什么规则的地方,我不知道。您可以考虑使用诸如“\w[\w/.]*\w”之类的正则表达式来获取以字母数字开头和结尾但可以包含斜杠和点的文件名。或者您可以通过多种方式细化/扩展规则。一个非常容易接受的正则表达式是'[^#]+';它接受除了两个哈希标记之间的哈希之外的任何内容。
【解决方案2】:
REPLACEMENT=`identify filename`
sed "s/#filename#/$REPLACEMENT/g"

编辑:见丹尼斯威廉姆森的评论。

【讨论】:

  • 您需要将单引号更改为双引号才能正常工作。 # 不需要转义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-17
  • 2020-02-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多