问题
我得到了一个管道分隔的文本文件,其中包含每个文件的文件名和一些索引信息。我的目标是使它成为一个制表符分隔的文件。但是,我想知道空条目在哪里。这将完成,例如当lorem||dolor变成lorem'\t'<empty>'\t'dolorsed时。
让我再举几个例子来说明我得到了什么和想要什么:
有多行的示例:(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个连续的空条目)
澄清
解决方案不必是awkgreptrperlpython等。这些只是我看到的解决方案。也欢迎使用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/

10-15 16:08