在bash中使用sed放置换行符,正则表达式的问题

时间:2014-02-03 22:17:26

标签: regex bash sed awk

大家好,我的数据看起来像这样

  samplename 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 ...
  samplename2 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 ...

我希望它看起来像这样:

  >samplename
  0 1 1 1 1 1 1 1 1 1 
  1 0 0 0 0 0 0 0 0 ...
  >samplename2 
  0 0 0 0 0 1 1 1 1 1 
  1 1 1 1 1 1 0 0 0 ...

[注意 - 每10个数字后显示换行符;我实际上在每200个之后就想要它,但我意识到显示这样的一行不会很有帮助]。

我可以在文本编辑器上使用正则表达式,但我想在bash中使用sed命令,因为我必须多次这样做,每行需要200个字符。

我尝试了这个,但收到了一个错误:

sed -e "s/\(>\w+\)\s\([0-9]+\)/\1\n\2" < myfile > myfile2

sed:1:“s /(&gt; \ w +)\ s([0-9] +)/ ...”:替换模式中未转义的换行符

还有一点需要注意 - 我在Mac上这样做;我知道Mac上的sedgnu sed略有不同。如果你能够给我一个适用于Mac的解决方案,那就太好了。

提前致谢。

5 个答案:

答案 0 :(得分:1)

根据您在200个号码后添加的换行请求,您最好使用awk

echo "hello 1 2 3 4" | awk '{print ">"$1; for(i=2; i<=NF; i++) {printf("%d ",$i); if((i+1)%2 == 0) printf("\n");}}

打印出来

>hello
1 2 
3 4 

如果您希望在仅以hello开头的行上 ,则可以修改为

echo "hello 1 2 3 4" | awk '/^hello / {print ">"$1; for(i=2; =NF; i++) {printf("%d ",$i); if((i+1)%2 == 0) printf("\n");}}

/ /中的正则表达式“仅在与此表达式匹配的行上执行此操作”。

您可以将语句if( (i + 1) % 2 == 0)修改为if( (i + 1) % 100 == 0 )以获得100位数后的换行符...我只是将其显示为2,因为打印输出更具可读性。

更新以使其更清洁,请执行以下操作。

使用以下内容创建文件调用breakIt :(如果您不想仅选择以“hello”开头的行,请忽略/^hello /;但请在代码周围留出{},这很重要。)

/^hello/ { print ">"$1;
   for(i=2; i<=NF; i++)
   {
      printf("%d ",$i);
      if((i+1)%100 == 0) printf("\n");
   }
   print "";
}

现在您可以发出命令

awk -f breakIt inputFile > outputFile

这表示“使用breakIt的内容作为处理inputFile的命令,并将结果放入outputFile”。

应该为你做好准备。

编辑以防万一你真的想要一个sed解决方案,这是一个很好的解决方案(好吧我想是这样)。将以下内容复制到名为sedSplit

的文件中
s/^([A-Za-z]+ )/>\1\
/g
s/([0-9 ]{10})/\1\
/g
s/$/\
/g

这有三个连续的sed命令;这些都是各自的,但由于它们插入换行符,它们实际上似乎需要六行。

s/^                  - substitute, starting from the beginning of the line
([A-Za-z]+ )/        - substitute the first word (letters only) plus space, replacing with 
>\1\
/g                   - the literal '>', then the first match, then a newline, as often as needed (g)

s/([0-9] ]{10})/     - substitute 10 repetitions of [digit followed by space]
\1\
/g                   - replace with itself, followed by newline, as often as needed

s/$/\
/g                   - replace the 'end of line' with a carriage return

您可以像这样调用此sed脚本:

sed -E -f sedSplit < inputFile > outputFile

这使用

-E标志(使用扩展正则表达式 - 不需要转义括号等)

-f标记('从此文件中获取指令')

它使整个事情变得更加清洁 - 并为您提供Mac上要求的输出(即使有额外的回车分离组;如果您不想要,请忽略最后两行)。

答案 1 :(得分:1)

$ awk '{print ">" $1; for (i=2;i<=NF;i++) printf "%s%s", $i, ((i-1)%10 ? FS : RS)}' file
>samplename
0 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 ...
>samplename2
0 0 0 0 0 1 1 1 1 1
1 1 1 1 1 1 0 0 0 ...

答案 2 :(得分:1)

fold是你的朋友:

sed 's/\([^ ]*\) /\1\n/' input | fold -w 100

答案 3 :(得分:0)

在双引号中,反斜杠由shell解释。其中任何一个都应该有用。

sed -e 's/\(>\w+\)\s\([0-9]+\)/\1\n\2/' < myfile > myfile2
sed -e "s/\\(>\\w+\\)\\s\\([0-9]+\\)/\\1\\n\\2/" < myfile > myfile2

PS,我添加了终止斜杠。你有一个s / ... / ...而不是s /.../.../

PS,因为我正在看你的正则表达式,sed会抱怨没有结束。试试这个。

sed -e 's/^\(\w\+\)\s\+/>\1\n/' < myfile > myfile2

MAC版本,限制为200个字符(100个单位和100个空格)

sed -Ee 's/^([a-zA-Z0-9]+) />\1\
/' | sed -Ee 's/(([0-9] ){99}[0-9]) /\1\
/g' < myfile > myfile2

第一个sed将字符串与数字分开,第二个sed将行分开。

答案 4 :(得分:0)

普通的bash:

while read -r name values; do
    printf ">%s\n%s\n" "$name" "$values"
done <<END
samplename 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 ...
samplename2 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 ...
END
>samplename
0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 ...
>samplename2
0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 ...

假设samplename不包含空格