问题
我得到了一个管道分隔的文本文件,其中包含每个文件的文件名和一些索引信息。我的目标是使它成为一个制表符分隔的文件。但是,我想知道空条目在哪里。这将完成,例如当lorem||dolor
变成lorem
'\t'
<empty>
'\t'
dolor
sed
时。
让我再举几个例子来说明我得到了什么和想要什么:
有多行的示例:(N.B.每行有相同数量的条目。)
鉴于:
||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个连续的空条目)
澄清
解决方案不必是
awk
、grep
、tr
、perl
、python
等。这些只是我看到的解决方案。也欢迎使用sed
或<empty>
脚本(或任何其他我没有想到的想法)。我的尝试和研究
对于我在研究之前和研究期间所做的尝试,命令和它们的输出作为图像1和文本文件2包含,以避免问题过于混乱。
My Attempts image
My Attempts text
链接到我查找的内容--查找带有
>
的连续管道(并替换任何此类管道系列):ref.here;计算空字段的数量(可能有助于了解需要多少个^I
):ref.here;最长序列:refhere;系统信息
$ 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键等,您将看到并需要键入此内容。无法复制/粘贴,因为
bash
仅在您在上一行按enter键后才显示。)$ 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>$
其中
'\t'
是我的<empty>
版本显示labore
的方式。通过使用我给出的示例文本给出的答案,我意识到我希望在'\t'
之后的结尾处有一个labore
(参见下面的命令)。请注意,收到的答案(感谢@Neil_McGuigan和@Ed_Morton)在<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
。这是我的错,因为我在最初的描述中不够清楚。我很抱歉。我只需稍微调整一下@Neilôu McGuigan的命令就可以完成我的目标。注意,如果您想如图所示逐行键入这个“line-by-line”,您需要在每行的末尾包括一个空格和一个
stderr
。$ 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
的空条目的计数是不必要的,但这很好。)对不起,我不清楚我想要什么。
我成功使用的东西
多亏了“尼尔·麦奎根”和“埃德·莫顿”,我才找到了我正在寻找的解决方案。我的最后命令如下:
$ 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键等,您将看到并需要键入此内容。无法复制/粘贴,因为
^I
仅在您在上一行按enter键后才显示。)$ 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
现在,相同的命令没有到
'\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
最佳答案
awk '
{
$1=$1;
for(i=1; i<NF; i++) {
if($i=="") { $i="<empty>"; empty++ }
};
print
}
END { print empty" empty" | "cat 1>&2"; }
' FS='|' OFS=$'\t'
应该会成功的。$1=$1告诉awk“重建”输入字段,以便它们可以与新的OutputFieldSeparator(OFS)一起使用。
print empty" empty" | "cat 1>&2"
将“n empty”打印到stderr。如果你愿意可以省略关于regex - 管道分隔的文件,其中有空条目;转换为制表符分隔的,中间用'<empty>',我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38880006/