这个问题的目的是提供一个规范的答案.
给定可能由Excel或其他具有嵌入换行符的工具生成的CSV,嵌入式双引号和空字段,如:
$ cat file.csv
"rec1, fld1",,"rec1"",""fld3.1
"",
fld3.2","rec1
fld4"
"rec2, fld1.1
fld1.2","rec2 fld2.1""fld2.2""fld2.3","",rec2 fld4
Run Code Online (Sandbox Code Playgroud)
使用awk识别单独记录和字段的最有效方法是什么:
Record 1:
$1=<rec1, fld1>
$2=<>
$3=<rec1","fld3.1
",
fld3.2>
$4=<rec1
fld4>
----
Record 2:
$1=<rec2, fld1.1
fld1.2>
$2=<rec2 fld2.1"fld2.2"fld2.3>
$3=<>
$4=<rec2 fld4>
----
Run Code Online (Sandbox Code Playgroud)
所以它可以在awk脚本的其余部分内部用作那些记录和字段.
有效的CSV将符合RFC 4180或可由MS-Excel生成.
解决方案必须允许记录结束只是LF(\n
),这是UNIX文件的典型情况,而不是CRLF(\r\n
),正如标准所要求的那样,Excel或其他Windows工具会生成.它还可以容忍与引用字段混合的未加引号的字段.它特别不需要容忍"
使用前面的反斜杠转义s(即\"
代替""
),因为其他一些CSV格式允许 - 如果你有,那么添加一个gsub(/\\"/,"\"\"")
前端将处理它并尝试在一个脚本中自动处理两个转义机制将使脚本不必要地脆弱和复杂.
我一直争辩说你永远不应该使用范围表达式,如:
/start/,/end/
Run Code Online (Sandbox Code Playgroud)
在awk中,因为虽然它只是简单的情况,你只想打印匹配的文本,包括起始和结束线比替代*更简洁:
/start/{f=1} f{print; if (/end/) f=0}
Run Code Online (Sandbox Code Playgroud)
当你想稍微调整它以做任何其他事情时,它需要完全重写或导致重复或其他不需要的代码.例如,如果您想使用上面的第二个表单打印除范围分隔符之外的匹配文本,您只需调整它以移动组件:
f{if (/end/) f=0; else print} /start/{f=1}
Run Code Online (Sandbox Code Playgroud)
但是如果你从一开始/start/,/end/
就需要放弃那种方法来支持我刚发布的内容,或者你必须写下这样的内容:
/start/,/end/{ if (!/start|end/) print }
Run Code Online (Sandbox Code Playgroud)
即重复不希望的条件.
然后我看到一个问题,要求end
在文件中识别LAST ,并在解决方案中使用范围表达式,我认为这似乎有一些价值(请参阅/sf/answers/1480150661/).
但现在,我又回想起根本不值得使用范围表达式,并且不使用范围表达式的解决方案也适用于该情况.
那么 - 有没有人有一个例子,其中范围表达式实际上为解决方案增加了显着的价值?
*我以前用过:
/start/{f=1} f; /end/{f=0}
Run Code Online (Sandbox Code Playgroud)
但是很多次我发现我必须做一些额外的事情,当它f
是真的并且/end/
被发现时(或者换一种方式只做一些事情,如果/end/
发现IF f
是真的那么)所以现在我只是试着坚持稍微不那么简短但更多强大且可扩展:
/start/{f=1} f{print; if (/end/) f=0}
Run Code Online (Sandbox Code Playgroud) 注意:这不是任何现有问题的重复,它旨在说明为什么这样一个极其常见且看似简单的问题无法回答,并提供有关发布此类问题的人如何修改它们以使其可回答的指导,因此我们不必几乎每天都在评论中提供相同的指导,并且可以参考这个。
给定以下输入文件:
foo
o.b
bar
Run Code Online (Sandbox Code Playgroud)
我需要输出与模式匹配的所有行,o.b
因此我的预期输出是:
o.b
Run Code Online (Sandbox Code Playgroud)
我已经尝试过,awk '"o.b"' file
但是输出所有行(添加这部分是为了避免抱怨没有在问题中发布尝试的解决方案)。
我有一个运行的命令,它给出了如下输出:
{
"endpointApplications": {
"App_Name": {
"connectionState": "Disconnected",
"connectionTime": "No connection was established",
"linkAttributes": {
"ackSettings": {
"dataAckEnabled": "true",
"dataAckTimeout": "5000",
"dataNakRetryLimit": "0",
"retransmitDelay": "500"
},
"keepAliveSettings": {
"keepAliveAckTimeout": "5000",
"keepAliveInterval": "30000"
},
"logTraffic": "false",
"port": "9999",
"role": "server"
},
"protocol": "snmp"
}
},
"queueStats": {}
}
Run Code Online (Sandbox Code Playgroud)
我需要输出如下所示:
{"endpointApplications": {"app_name": {"connectionState": "Disconnected","connectionTime": "No connection was established","linkAttributes": {"ackSettings":{"dataAckEnabled": "true","dataAckTimeout": "5000","dataNakRetryLimit": "0","retransmitDelay": "500"},"keepAliveSettings":{"keepAliveAckTimeout": "5000","keepAliveInterval": "30000"},"logTraffic": "false","port": "9999","role": "server"},"protocol": "snmp"}},"queueStats":{}}
Run Code Online (Sandbox Code Playgroud)
我尝试使用awk和sed结合不同的参数,但我无法在不丢失JSON格式的情况下开始工作.
这个问题的目的是提供一个答案,每天的问题,其答案是"你中有DOS行结束",所以我们可以简单地关闭他们,因为这一个的副本,而无需重复同样的答案,令人生厌.
注意:这不是任何现有问题的副本.本问答的目的不仅仅是提供"运行此工具"的答案,而且还要解释这个问题,以便我们可以在这里指出任何有相关问题的人,他们会找到一个明确的解释,为什么他们在这里也被指出作为运行的工具,解决他们的问题.我花了几个小时阅读所有现有的问答,他们都缺乏对问题的解释,可用于解决问题的替代工具,和/或可能的解决方案的优缺点/警告.他们中的一些人已经接受了一些非常危险且永远不应该使用的答案.
现在回到将导致推荐的典型问题:
我有一个包含1行的文件:
what isgoingon
Run Code Online (Sandbox Code Playgroud)
当我使用这个awk脚本打印它来反转字段的顺序时:
awk '{print $2, $1}' file
Run Code Online (Sandbox Code Playgroud)
而不是看到我期望的输出:
isgoingon what
Run Code Online (Sandbox Code Playgroud)
我得到的行应该在行的末尾出现在行的开头,覆盖行开头的一些文本:
whatngon
Run Code Online (Sandbox Code Playgroud)
或者我将输出拆分为2行:
isgoingon
what
Run Code Online (Sandbox Code Playgroud)
问题是什么,我该如何解决?
我正在尝试编写一个sed脚本,它将捕获文本文件中的所有"裸"URL并将其替换为<a href=[URL]>[URL]</a>
."裸"是指未包含在锚标记内的URL.
我最初的想法是,我应该匹配在他们面前没有"或"的URL,并且在他们之后也没有<或a".然而,我在表达"不要在前面或后面"的概念时遇到了困难,因为据我所知,sed没有前瞻或后视.
样本输入:
[Beginning of File]http://foo.bar arbitrary text
http://test.com other text
<a href="http://foobar.com">http://foobar.com</a>
Nearing end of file!!! http://yahoo.com[End of File]
Run Code Online (Sandbox Code Playgroud)
样本期望输出:
[Beginning of File]<a href="http://foo.bar">http://foo.bar</a> arbitrary text
<a href="http://test.com">http://test.com</a> other text
<a href="http://foo.bar">http://foo.bar</a>
Nearing end of file!!! <a href="http://yahoo.com">http://yahoo.com</a>[End of File]
Run Code Online (Sandbox Code Playgroud)
注意第三行未经修改,因为它已经在里面<a href>
.另一方面,第一行和第二行都被修改.最后,请注意所有非URL文本都是未修改的.
最终,我想做的事情如下:
sed s/[^>"](http:\/\/[^\s]\+)/<a href="\1">\1<\/a>/g 2-7-2013
Run Code Online (Sandbox Code Playgroud)
我首先验证以下内容是否正确匹配并删除了一个URL:
sed 's/http:\/\/[^\s]\+//g'
Run Code Online (Sandbox Code Playgroud)
然后我尝试了这个,但它无法匹配从文件/输入开头开始的URL:
sed 's/[^\>"]http:\/\/[^\s]\+//g'
Run Code Online (Sandbox Code Playgroud)
有没有办法在sed中解决这个问题,可以通过模拟lookbehind/lookahead,还是明确匹配文件的开头和文件结尾?
input.txt
:
blah1
blah2
start_pattern
blah3
blah4
blah5
end_pattern
blah6
blah7
Run Code Online (Sandbox Code Playgroud)
我想input.txt
成为:
blah1
blah2
end_pattern
blah6
blah7
Run Code Online (Sandbox Code Playgroud)
我尝试了以下,但它没有用.
sed -i "/start_pattern/, /end_pattern/{$!d}" input.txt
Run Code Online (Sandbox Code Playgroud) 在Linux上,这按预期运行:
$ echo -e "line1\r\nline2"|awk -v RS="\r\n" '/^line/ {print "awk: "$0}'
awk: line1
awk: line2
Run Code Online (Sandbox Code Playgroud)
但在windows下\ r \n被删除(awk认为这一行):
视窗:
$ echo -e "line1\r\nline2"|awk -v RS="\r\n" '/^line/ {print "awk: "$0}'
awk: line1
line2
Run Code Online (Sandbox Code Playgroud)
Windows GNU Awk 4.0.1 Linux GNU Awk 3.1.8
来自@EdMorton的编辑(对不起,如果这是一个不需要的补充,但我认为这可能有助于证明问题):
考虑这个RS设置和输入(在cygwin上):
$ awk 'BEGIN{printf "\"%s\"\n", RS}' | cat -v
"
"
$ echo -e "line1\r\nline2" | cat -v
line1^M
line2
Run Code Online (Sandbox Code Playgroud)
这是带有gawk的Solaris:
$ echo -e "line1\r\nline2" | awk '1' | cat -v
line1^M
line2
Run Code Online (Sandbox Code Playgroud)
这是与gawk的cygwin:
$ echo -e "line1\r\nline2" | …
Run Code Online (Sandbox Code Playgroud) 是否存在与基本R 函数等效的字符串grep
?
我想要匹配的字符串的索引.例:
grep("F|Y", LETTERS)
[1] 6 25
Run Code Online (Sandbox Code Playgroud)
使用stringr我的解决方法将使用which
如下:
which(str_detect(LETTERS, "F|Y"))
[1] 6 25
Run Code Online (Sandbox Code Playgroud) 我试图用命令的输出填充关联数组。我可以在没有命令的情况下做到这一点:
$ declare -A x=( [first]=foo [second]=bar )
$ echo "${x[first]}, ${x[second]}"
foo, bar
Run Code Online (Sandbox Code Playgroud)
我可以用命令输出填充一个非关联数组:
$ declare y=( $(echo 'foo bar') )
$ echo "${y[0]}, ${y[1]}"
foo, bar
Run Code Online (Sandbox Code Playgroud)
但是当我尝试在上述两个基础上构建一个语句来从命令填充关联数组时,我收到以下错误消息:
$ declare -A z=( $(echo '[first]=foo [second]=bar') )
-bash: z: $(echo '[first]=foo [second]=bar'): must use subscript when assigning associative array
Run Code Online (Sandbox Code Playgroud)
为什么我会收到该错误消息以及使用命令输出填充关联数组的正确语法是什么?我试图避免使用eval
用于通常的原因,不想使用临时文件,当然echo
只是被用作产生问题的效果的命令的例子,真正的命令将更加复杂。
因此,根据以下几个答案,看起来只是我的引用有问题:
$ declare -A z="( $(echo '[first]=foo [second]=bar') )"
$ echo "${z[first]}, ${z[second]}"
foo, bar
Run Code Online (Sandbox Code Playgroud)
并在索引和值中有空格:
$ declare -A z="( $(echo '[first field]="foo with …
Run Code Online (Sandbox Code Playgroud)