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.*
。 -d
POSIX 不要求和-n
选项。请查看您的操作系统以了解是否可以使用它们。这里指定换行符作为分隔符,指示每个.仅使用两个输入项,如果支持,则可能有些限制。xargs
man 1 xargs
-d '\n'
-n 2
xargs
copy
-n
上述方法在很多情况下都有效,但如果我是你,我会使用 shell 及其read
内置功能。这是真的不应循环read
解析文本;sed
和awk
等通常都是合适的工具。但是在这里,您的目标不仅仅是解析文本。您的目标是编写和运行命令。像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)
}'
但还是存在一些问题:
- 引用狂潮。有三个级别需要引用并解释它们:
awk
调用的原始 shell、awk
本身、调用的 shell 。可以通过构建脚本(使用类似 的 shebang )system()
来摆脱第一级。但它仍然很麻烦。我甚至不确定我是否按照我想要的方式放置了这些引号。awk
#!/usr/bin/awk
cmdline
作为字符串传递,然后解析,而不是作为参数数组。如果输入包含文字'
字符,则会出现问题,输入的某些部分可能会被执行(代码注入!)。system(cmdline)
调用sh
,每行都有一个额外的独立 shell。您可以print cmdline
改为将整个输出通过管道传输到单个 shellsh
(或保存到文件以便稍后解析)。这将减少进程数,但之前的问题仍然存在:文本输出将是解析迟早。
根据我的经验,我可以说这些问题不仅限于awk
。如果您想使用任何工具来运行基于任意输入的参数的外部命令,请注意它是传递字符串(要解析sh
或任何其他内容)还是生成具有严格定义的参数数组的新进程。例如,find -exec
后者(或至少是find
do 的常见实现)。
结论:
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"'/;'