您可以多次调用 sed ,而无需使用多个管道,只需用(谢谢大家……)来分隔 cmd,;
有没有办法将其用于多个awk -F
cmd?
使用sed
多个管道
echo "'text';" | \
sed s"#';##"g | \
sed s"#'##"g
text
使用sed
with;
作为分隔符
echo "'text';" | \
sed " \
s#';##g; \
s#'##g \
"
text
编辑:
因此,您可以awk
使用 加入多个 cmd ;
。但不能对多个awk -F
cmd执行此操作
问题是关于串联多个 awk -F
命令,这仍然没有答案。
背景
# '/x/ gives the href of the actual videos
# awk -F '/x/' '{print$2}’
# because the /x/ is unique to the video urls
# after this the video links appear
# but I have to get rid of stuff
# on the right of them so I do
# awk —F 'title' '{print$1}'
# this returns all the video links
# but they have a double quotes
# and a semi colon on the end.
curl -s \
https://site.com/plist/page={0..50} | \
grep '/x/' | \
awk -F '/x/' '{print$2}' | \
awk -F 'title' '{print$1}' | \
sed ' \
s#";##g; \
s#"##g \
'
所以现在我有一堆视频链接并进行进一步处理以获得视频下载链接,然后我使用mapfile
将下载链接获取到数组中并用于parallel
下载它们。
我缩短了在该代码示例中实际执行的许多内容。
编辑:
所以这是做不到的。非常感谢该用户。
该用户评论说sed
用于我的一个特定案例,这将消除需要,awk -F
但我至少还有 20 个其他案例。但它给了我一些思考,我这样做的原因,awk -F
是因为它在不了解任何 sed 正则表达式的情况下为我提供了我需要的东西。
不管怎样,谢谢大家,我想知道是否可以做到,但不能,所以我很满意。
谢谢
对于@StèphaneChazelas,他们的评论解决了我的问题。
答案1
更新:问题是大幅改变发布此答案后,因此原始答案 - 虽然仍然正确 - 对解决问题没有多大帮助实际的OP的问题。
您似乎尝试处理curl
表单的输出
Ignore this
http://some.url.involving/x/'video-link-1';title...
http://some.url.involving/x/'video-link-2';title...
Ignore that
等等,你想去的地方
- 仅处理出现的行
/x/
,并且 - 提取中间的部分
' ... '
最简单的方法是仅使用一个字段分隔符,即'
:
curl -s https://site.com/plist/page={0..50} | awk -F"'" '/\/x\//{print $2}'
此外,这将仅考虑包含该/x/
模式的行。因此,对于上面的例子,输出将是
video-link-1
video-link-2
如果您想通过更改字段分隔符进行拆分来做到这一点,您当然可以FS
按照中所示中途更改内部变量斯蒂芬·查泽拉斯的回答。但是,在这种情况下,我宁愿使用这样一个事实:多字符字段分隔符,无论是通过-F
作为选项参数设置还是通过程序FS
内部的赋值设置awk
,都被视为完整的正则表达式。
这意味着您可以使用“或”类型替代作为字段分隔符来涵盖两种情况(但您还应该包括单引号和分号以避免进一步的后处理需要):
curl -s https://site.com/plist/page={0..50} |
awk -F'/x/\047|\047;title' '/\/x\//{print $2}'
- 这会将字段分隔符设置为任何一个
/x/'
或者';title
。 - 它只会考虑包含该
/x/
模式的行。在这些行上,它将打印第二个字段,这是您想要的信息(并且已经删除了'
和;
)。 - 单引号表示为 ASCII 代码,
\047
以避免出现“单引号内的单引号”问题(我只是假设您的操作系统是基于 ASCII 的系统,而不是EBCDIC)。
另一种经常遇到的方法是“仅用有趣的部分替换整行”,如
curl -s https://site.com/plist/page={0..50} |
awk '/\/x\//{print gensub(/.*\/x\/\047([^\047]+).*/,"\\1","1")}'
这将再次仅考虑模式/x/
出现的行,用遵循该模式的单引号之间的内容替换整行,并打印修改后的行以仅提取该部分。
单个sed
调用也可以实现同样的效果,尽管通过 ASCII 代码表示单引号在这里不起作用,因此涉及的内容更多一些。假设 GNUsed
具有-E
ERE 选项:
curl -s https://site.com/plist/page={0..50} | sed -n -E 's|.*\/x\/'\''([^'\'']+).*|\1|p'
这将默认抑制输出-n
,像案例一样执行替换awk
,然后打印(尾随p
)仅当进行替换时,这意味着已找到该模式。/x/'video-link';title
原答案如下
框架挑战:有必要吗?
在 中awk
,您可以根据需要多次重复同一程序中的任何修改命令,如
echo "'text';" | awk '{gsub(/\047;/,""); gsub(/\047/,"")} 1'
或者
echo "'text';" | awk '{gsub(/\047;/,"")} {gsub(/\047/,"")} 1'
(用于\047
在单引号程序中表达单引号)。
你也可以用一种易于阅读的方式写下来,比如
echo "'text';" |
awk '{gsub(/\047;/,"")};
{gsub(/\047/,"")}; 1'
或作为专用程序:
echo "'text';" | awk -f multi-substitute.awk
看起来multi-substitute.awk
像
#!/usr/bin/awk -f
{gsub(/\047;/,"")}
{gsub(/\047/,"")}
1
答案2
有什么问题:
echo "'text';" | sed "
s/';//g
s/'//g
"
或者:
awk -v q="'" '
{
gsub(q ";", "")
gsub(q, "")
print
}'
或者:
awk -v q="'" '
{
gsub(q ";", "")
}
{
gsub(q, "")
}
{
print
}'
对于这个问题?
不需要几个-e
s。也许除了 (t)csh 是 PITA 之外,大多数 shell 都可以完全满足您输入多行参数的要求。
-e arg
insed
实际上指定为在代码arg
中添加换行符sed
,因此
sed -e foo -e bar
意味着与
sed 'foo
bar'
没有什么可以阻止你也做:
NL='
' # or NL=$'\n' with most modern shells.
sed_cmd1='s/foo/bar' awk_cmd1='gsub(/foo/, "bar")'
sed_cmd2='s/bar/baz' awk_cmd2='gsub(/bar/, "baz")'
sed "$sed_cmd1$NL$sed_cmd2"
# or
awk "{$awk_cmd1$NL$awk_cmd2${NL}print}"
或者:
awk "$(printf '%s\n' '{gsub("foo", "bar"}' '{gsub("bar", "baz")}')"
在awk
语法上,您可以用 with 替换换行符来分隔命令;
。也可以sed
,但仅在有限数量的命令之后(不在w
, r
, :
, a
, c
, , i
, b
, t
,}
或#
命令之后s
,如果w
例如使用了标志,至少是可移植的)。
为了避免担心引用,您还可以这样做:
awk "$(<<'EOF' cat
{
gsub("';", "") # ' " \ not a problem
gsub("'", "")
print
}
EOF
)"
或者在大多数系统上:
awk -f /dev/fd/3 3<<'EOF'
{
gsub("';", "") # ' " \ not a problem
gsub("'", "")
print
}
EOF
(请注意第一个周围的引号,EOF
以确保此处文档中的 shell 不会执行任何扩展)
至于您对多个-F
s 的编辑(不要与 混淆-f
):
-F x
是将字段分隔符设置为x
,与-v FS=x
或添加一个BEGIN { FS = "x" }
.
例如,这样做-F ' ' -F '|' -F ','
不会帮助您获得第二个空格,
分隔字段的第三|
个分隔字段的第一个分隔字段。foo a|b|x,y,z|c bar
那只会设置FS
为,
.
为此你需要:
awk '
{
split($0, a, " ")
split(a[2], b, "|")
split(b[3], c, ",")
print c[1]
}'
或者使用FS
:
awk '
{
FS = " "; $0 = $2
FS = "|"; $0 = $3
FS = ","; print $1
}'
FS
这里使用where来在访问(x >= 1)$0
时分割(最初是当前记录的内容) 。$x
IOW,能够减少
awk '{print "something out of "$0}' |
awk '{print "something out of "$0" as modified by the first}'
你需要:
awk '
{
$0 = "something out of "$0
print "something out of "$0" as modified by the first
}'
您可以轻松地减少两个sed
ss/x/y/
各做一个或相当于两个awk
s 做{gsub("x", "y"); print}
,但您不一定对任何sed
或awk
代码应用相同的配方,您只需要了解它们如何工作以及它们一次处理一条记录当文本流进来时。
答案3
sed
和-e
echo "'text';" | sed s"#';##"g | sed s"#'##"g text echo "'text';" | sed -e s"#';##"g -e s"#'##"g text
通常不需要使用多个命令,也不需要使用-e
两次(只需使用分号)。允许 awk 或 sed 的单个实例处理这两项操作可能会更快。
$ echo "'text';" | sed "s/';//g; s/'//g"
text
我可能已经使用捕获来完成此操作
$ echo "'text';" | sed -r "s/'([^']*)';/\1/g"
text
当然,我毫不怀疑您的简单示例是一对无法以这种方式轻松组合的程序的占位符。不过我不希望新手有错误的印象。简单的操作最好以这种方式组合起来。
awk
和-F
curl -s \ https://site.com/plist/page={0..50} | \ grep '/x/' | \ awk -F '/x/' '{print$2}' | \ awk -F 'title' '{print$1}' | \ sed ' \ s#";##g; \ s#"##g \ '
对于 AWK,正如其他人指出的那样,与其尝试为不同的表达式设置不同的字段分隔符,不如完全使用不同的方法。如果正则表达式可以充分表达要遇到的所有数据的结构,那么这可能是从具有混合分隔符的字符串中提取项目的最佳方法。正则表达式经常被过度使用,但它们不应该被忽视。
鉴于此数据:
$ cat /tmp/titles.txt
preamble
p/q/r/s/title"Not This";Brick
something
a/x/b/c/title"The Rime of the Ancient Mariner";Coleridge
otherthing
f/g/x/h/title"Jackass";Knoxville
remainder
我可能会尝试在 Perl 中完成上述全部任务
$ curl -s file:///tmp/titles.txt | \
> perl -n -e 'print "$1\n" if m{/x/.*title"([^"]*)";}'
The Rime of the Ancient Mariner
Jackass
使用 Curl 和单个 AWK 程序可能可以轻松完成此操作。我不是 AWK 专家,但我可能会从以下内容开始并完善它
$ curl -s file:///tmp/titles.txt | \
> awk '/\/x\// {gsub(".*title\"",""); gsub("\";.*",""); print}'
The Rime of the Ancient Mariner
Jackass
(Gnu Sed 4.2.2、Perl 5.18.2。Gnu AWK 4.0.1)
答案4
如果你有一个漂亮的 GNUawk
那么是的
% printf abc'\n' | gawk -e '{print}' -e '{print}'
abc
abc
否则,可能不会。
% printf abc'\n' | awk -e '{print}' -e '{print}'
awk: unknown option -e ignored
awk: can't open file -e
source line number 1
使用像 ZSH 这样的花哨 shell,您可以执行如下所示的可怕操作,但此时您可能应该将脚本放入正确的文件中并运行它。
% print -l abc | awk -f <(print "{print}") -f <(print "{print}")
abc
abc