重用 sed 流进行字符串附加

重用 sed 流进行字符串附加

TL;DR:需要重用 sed 中的流,以便将提取的字符串添加到当前行的结尾。

我有一个extract使用 sed 的子字符串脚本,并使用这个子字符串的名称创建了一个复制命令。

我尝试了一些方法,例如 xargs,但sed -e分别解析每一行并重新调用 sed 再次读取当前正在解析的每一行的所有行:

下面这一行仅打印出提取的字符串:

cat hello.txt | sed -e 's/.*search_start\(.*\)search_end*/\1/' | xargs -I@ "echo ./@"

此行创建一个字符串,并为文件夹添加复制命令location

cat hello.txt | sed -e 's/\(^\)/copy /; s/$/ .\/location/;'

但是,我想将它们加在一起,以便extracted_str可以在此处引用搜索到的字符串来代替location文件夹。因此,我需要类似这样的内容(针对每一行):

copy input_sed_line extracted_str

答案1

如果我理解正确的话,您需要额外出现整行以及sed从中摘录的任何内容。好吧,sed可以使用 打印整行p,因此这是可能的:

< hello.txt sed -e 'p; s/.*search_start\(.*\)search_end.*/\1/' | xargs -d '\n' -n 2 copy --

笔记:

  • 无论copy是什么(你的意思是什么cp?)。
  • 我假设copy理解--(选项标记的结束)。
  • 我修复了 的无用用法cat
  • 我认为search_end*应该是search_end.*
  • -dPOSIX 不要求和-n选项。请查看您的操作系统以了解是否可以使用它们。这里指定换行符作为分隔符,指示每个.仅使用两个输入项,如果支持,则可能有些限制。xargsman 1 xargs-d '\n'-n 2xargscopy-n

上述方法在很多情况下都有效,但如果我是你,我会使用 shell 及其read内置功能。这是真的不应循环read解析文本;sedawk等通常都是合适的工具。但是在这里,您的目标不仅仅是解析文本。您的目标是编写和运行命令。像sh或 这样的 shellbash是运行命令的合适工具。

#!/bin/sh

while IFS= read -r wholeline; do
   target="$(printf '%s\n' "$wholeline" | sed -e 's/.*search_start\(.*\)search_end.*/\1/')"
   copy -- "$wholeline" "$target"
done < hello.txt

代码sed为每一行运行一个单独的进程。对于你的情况,这可以轻松避免:

#!/bin/sh

while IFS= read -r wholeline; do
   target="${wholeline##*search_start}"   # removing prefix
   target="${target%%search_end*}"        # removing postfix
   copy -- "$wholeline" "$target"
done < hello.txt

人们可以做(几乎)同样的事情awk

< hello.txt awk '{
   target=$0
   sub(/.*search_start/,"",target)
   sub(/search_end.*/,"",target)
   cmdline="copy -- '"'"'"$0"'"' '"'"target"'"'"'"
   system(cmdline)
   }'

但还是存在一些问题:

  1. 引用狂潮。有三个级别需要引用并解释它们:awk调用的原始 shell、awk本身、调用的 shell 。可以通过构建脚本(使用类似 的 shebang )system()来摆脱第一级。但它仍然很麻烦。我甚至不确定我是否按照我想要的方式放置了这些引号。awk#!/usr/bin/awk
  2. cmdline作为字符串传递,然后解析,而不是作为参数数组。如果输入包含文字'字符,则会出现问题,输入的某些部分可能会被执行(代码注入!)。
  3. system(cmdline)调用sh,每行都有一个额外的独立 shell。您可以print cmdline改为将整个输出通过管道传输到单个 shell sh(或保存到文件以便稍后解析)。这将减少进程数,但之前的问题仍然存在:文本输出将是解析迟早。

根据我的经验,我可以说这些问题不仅限于awk。如果您想使用任何工具来运行基于任意输入的参数的外部命令,请注意它是传递字符串(要解析sh或任何其他内容)还是生成具有严格定义的参数数组的新进程。例如,find -exec后者(或至少是finddo 的常见实现)。


结论:

  • xargs可能缺乏有用的选项。
  • 文本处理工具在处理文本方面比shell要好,但是在运行外部命令方面通常要差很多。

出于这个原因,我认为 shell 循环至少在这里是合理的。不过你还是应该阅读以下问题的好答案已经链接的问题。请注意,我的 shell 脚本并未遵循您在此处找到的所有提示。

答案2

为什么不:

location=$(cat hello.txt | sed -e 's/.*search_start\(.*\)search_end*/\1/' | xargs -I@ "echo ./@")
cat hello.txt | sed -e 's/\(^\)/copy /; s/$/ .\/'"$location"'/;'

相关内容