带有空条目的管道分隔文件;在

时间:2016-08-10 17:33:59

标签: regex bash awk sed delimited-text

问题

我收到了一个以管道分隔的文本文件,其中包含文件名和每个文件的一些索引信息。我的目标是使其成为制表符分隔文件。 但是,我想知道空条目的位置。这将完成,例如, lorem||dolor变为lorem '\t' <empty> '\t' dolor

让我举几个例子来说明我得到的和所期望的:

多行示例:( 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个连续的空条目。)

澄清

解决方案不一定是sedawkgreptr等。这些只是我看过的解决方案。我也欢迎perlpython脚本(或任何其他我没有想过的想法)。

我的尝试和研究

对于我在研究之前和研究期间所做的尝试,命令及其输出包含在图像 1 和文本文件 2 以免过度混乱这个问题。

My Attempts image

My Attempts text

我查找的内容的链接 - 使用sed查找连续的管道(并替换任何此类管道系列):ref。 here;计算空字段的数量(可能需要知道需要多少<empty>):ref。 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(因为这项工作需要它。)

EDIT1

我不清楚到底想要什么。

这是一个简短的例子,展示了我在开始和结束时对管道的要求:

(这是你会看到的,如果你输入第一行,点击输入,键入第二行,点击输入等,你需要键入它。它不能被复制/粘贴,因为{ {1}}仅在您在上一行按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>$ 是我的^I版本显示bash的方式。根据我给出的一些示例文本给出的答案,我意识到在'\t'之后我想要一个<empty>(参见下面的命令)。请注意,收到的答案(感谢@Neil_McGuigan和@Ed_Morton)在labore后提供'\t',而不是labore。这是我的错,因为我在原始描述中不够清楚。道歉。

我能够通过对@ Neil_McGuigan的命令进行一些调整来实现我的目标。请注意,如果您要按照所示“逐行”键入,则需要在每行的末尾添加一个空格和<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

(请注意,写入<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_McGuigan和@Ed_Morton,我能够得到我正在搜索的解决方案。我的最后命令如下:

stderr

万一你不想滚动,这里是相同的命令:

$ 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

$

以下是制作,转换和保存文件的示例:

(这是你会看到的,如果你输入第一行,点击输入,键入第二行,点击输入等,你需要键入它。它不能被复制/粘贴,因为{ {1}}仅在您在上一行按Enter后显示。)

$ 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

$

最后,让我们返回给我带来麻烦的字符串。我们可以得到如下所需的输出:

>

现在,相同的命令没有管道到$ 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 的{​​{1}};我们只会看到文本,因为它是“标签式”。

cat -A

2 个答案:

答案 0 :(得分:2)

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&#34;重建&#34;输入字段,以便它们可以与新的OutputFieldSeparator(OFS)一起使用。

print empty" empty" | "cat 1>&2"打印&#34; n清空&#34;到斯特德尔。如果您愿意,可以省略它

答案 1 :(得分:1)

您只需要执行|| - &gt; |<empty>|替换两次,无论该模式出现多少次,只要您每次都全局执行:

$ sed 's/||/|<empty>|/g; s/||/|<empty>|/g; s/|/\t/g' file
lorem   ipsum   <empty> sit     amet,   <empty> <empty> <empty> eiusmod tempor <empty>  <empty> labore

或者如果您更喜欢awk:

$ awk '{while(gsub(/\|\|/,"|<empty>|")); gsub(/\|/,"\t")} 1' file
lorem   ipsum   <empty> sit     amet,   <empty> <empty> <empty> eiusmod tempor <empty>  <empty> labore

对于某些seds,您可能需要'$'\t''而不只是\t