【发布时间】:2016-12-17 05:27:18
【问题描述】:
问题
我收到了一个以竖线分隔的文本文件,其中包含每个文件的文件名和一些索引信息。我的目标是使它成为一个制表符分隔的文件。 但是,我想知道空条目在哪里。这将完成,例如lorem||dolor 变成 lorem '\t' <empty> '\t' dolor。
让我再举几个例子来说明我得到了什么和想要什么:
多行示例:(注意,每行的条目数相同。)
给定:
||dolor|sit
amet,||adipiscing|
sed|do|eiusmod|tempor
期望:
<empty> '\t' <empty> '\t' dolor '\t' sit '\n'
amet, '\t' <empty> '\t' adipiscing '\t' <empty> '\n'
sed '\t' do '\t' eiusmod '\t' tempor '\n'
开头和结尾处为空条目。
给定:
|ut|labore||dolore||
期望:
<empty> '\t' ut '\t' labore '/t' <empty> '\t' dolore '\t' <empty> '\t' <empty>
(我不想要空格;我只是认为它会使所需的格式更易于阅读。)
问题在于连续的空条目。我得到的文件可以有 1 到 36 个连续的管道(0 到 37 个连续的空条目。)
澄清
解决方案不必是sed、awk、grep、tr 等。这些只是我看过的解决方案。 perl 或 python 脚本(或我没有想到的任何其他想法)也将受到欢迎。
我的尝试和研究
对于我在研究之前和期间所做的尝试,命令及其输出包含为图像1 和文本文件2 以便不要让问题过于混乱。
指向我查找的内容的链接 -- 使用 sed 查找连续管道(并替换任何此类管道系列):参考。 here ;计算空字段的数量(可能有助于了解需要多少 <empty>):参考。 here ;最长序列:ref here ;
系统信息
$ uname -a
CYGWIN_NT-10.0 A-1052207 2.5.2(0.297/5/3) 2016-06-23 14:29 x86_64 Cygwin
$ bash --version
GNU bash, version 4.3.42(4)-release (x86_64-unknown-cygwin) ...
$
我在 Windows 10 上运行这个版本的 Cygwin(因为工作需要它。)
编辑1
我不清楚到底想要什么。
这是一个简短的示例,展示了我希望在开头和结尾使用管道的效果:
(如果您输入第一行,按 Enter,输入第二行,按 Enter 等,您将看到并需要输入。它不能被复制/粘贴,因为 @ 987654347@ 仅在您在上一行按回车后显示。)
$ cat > myfile.txt<<EOF
> ||foo|||bar||
> EOF
$ <**command-to-be-used**> myfile.txt | cat -A
<empty>^I<empty>^Ifoo^I<empty>^I<empty>^Ibar^I<empty>^I<empty>$
^I 是我的bash 版本显示'\t' 的方式。从使用我给出的一些示例文本给出的答案中,我意识到我希望在最后一个 <empty> 之后,在 labore 之后(参见下面的命令)。请注意,收到的答案(感谢@Neil_McGuigan 和@Ed_Morton)在labore 之后给出'\t',而不是<empty>。这是我的错,因为我在最初的描述中不够清楚。我很抱歉。
我能够通过对@Neil_McGuigan 的命令稍作调整来实现我的目标。请注意,如果您想按所示“逐行”键入,则需要在每行末尾包含一个空格和一个 \。
$ echo "||lorem|ipsum||sit|amet,||||eiusmod|tempor|||labore|" |
awk '
{
$1=$1; n_empty=0;
for(i=1; i<=NF; i++)
{
if($i=="") {$i="<empty>"; n_empty++;}
};
print
}
END {print n_empty" entries are empty" | "cat 1>&2";}
' FS='|' OFS=$'\t'
| cat -A
给出结果:
<empty>^I<empty>^Ilorem^Iipsum^I<empty>^Isit^Iamet,^I<empty>^I<empty>^I<empty>^Ieiusmod^Itempor^I<empty>^I<empty>^Ilabore^I<empty>$
9 entries are empty
再一次,对于那些不想滚动的人,这个输出如下:
<empty>^I<empty>^Ilorem^Iipsum^I<empty>^Isit^Iamet,^I<empty>^I<empty>^I<empty>^Ieiusmod^Itempor^I<empty>^I<empty>^Ilabore^I<empty>$
9 entries are empty
(请注意,写入stderr 的空条目的计数不是必需的,但这很好。)
抱歉,我不清楚我想要什么。
我使用成功的东西
感谢@Neil_McGuigan 和@Ed_Morton,我能够获得我正在寻找的解决方案。我的最终命令如下:
$ awk '{$1=$1; n_empty=0; for(i=1; i<=NF; i++) {if($i=="") {$i="<empty>"; n_empty++;}}; print;} END {print n_empty" entries are empty" | "cat 1>&2";}' FS='|' OFS=$'\t' file_pipe-delim.txt > file_tab-delim.txt
$
以防万一您不想滚动,这里是相同的命令:
$ awk '{$1=$1; for(i=1; i<NF; i++){ if($(i)=="")$(i)="<empty>" }; print}'
FS='|' OFS=$'\t' file_pipe-delim.txt | sed 's/\t$/\t<empty>/g' >
file_tab-delim.txt
$
以下是制作、转换和保存文件的示例:
(如果您输入第一行,按 Enter,输入第二行,按 Enter 等,您将看到并需要输入。它不能被复制/粘贴,因为 @ 987654364@ 仅在您在上一行按回车后显示。)
$ cat > file_pipe-delim.txt<<EOF
> ||dolor|sit
> amet,||adipiscing|
> sed|do|eiusmod|tempor
> |||
> |aliqua.|Ut|
> EOF
$ awk '{$1=$1; n_empty=0; for(i=1; i<=NF; i++)
{if($i=="") {$i="<empty>"; n_empty++;}}; print;} END
{print n_empty" entries are empty" | "cat 1>&2";}'
FS='|' OFS=$'\t' file_pipe-delim.txt > file_tab-delim.txt
$ cat -A file_tab-delim.txt
<empty>^I<empty>^Idolor^Isit$
amet,^I<empty>^Iadipiscing^I<empty>$
sed^Ido^Ieiusmod^Itempor$
<empty>^I<empty>^I<empty>^I<empty>$
<empty>^Ialiqua.^IUt^I<empty>$
$
最后,让我们返回给我带来麻烦的字符串。我们可以得到想要的输出如下:
$ echo "||lorem|ipsum||sit|amet,||||eiusmod|tempor|||labore|" | awk '{$1=$1; n_empty=0; for(i=1; i<=NF; i++) {if($i=="") {$i="<empty>"; n_empty++;}}; print;} END {print n_empty" entries are empty" | "cat 1>&2";}' FS='|' OFS=$'\t' | cat -A
<empty>^I<empty>^Ilorem^Iipsum^I<empty>^Isit^Iamet,^I<empty>^I<empty>^I<empty>^Ieiusmod^Itempor^I<empty>^I<empty>^Ilabore^I<empty>$
9 entries are empty
现在,相同的命令没有cat -A 的管道,这意味着我们不会看到每个^I 的'\t';我们只会看到“标签”的文本。
$ echo "||lorem|ipsum||sit|amet,||||eiusmod|tempor|||labore|" | \
awk '{$1=$1; n_empty=0; for(i=1; i<=NF; i++) \
{if($i=="") {$i="<empty>"; n_empty++;}}; print;} END \
{print n_empty" entries are empty" | "cat 1>&2";}' \
FS='|' OFS=$'\t'
<empty> <empty> lorem ipsum <empty> sit amet, <empty> <empty> <empty>eiusmod tempor <empty> <empty> labore <empty>
9 entries are empty
【问题讨论】:
-
修复
a|||b中两个空字段的问题在于s/||/|<empty>|/g' or something similar is that the first match uses both the first two pipes, so when the scan continues, the third pipe is not paired. You can overcome that by repeating the original match:sed -e 's/||/||/g' -e 's/||/| |/g'` .但是,当您也更改分隔符时,您必须更加努力,但这就是出现问题的原因。 -
是的,我考虑过这个问题,这就是我没有尝试过那条路线的原因。看来@Ed_Morton 已经想通了。