【问题标题】:Putting line break using sed in bash, problems with regular expressions在 bash 中使用 sed 换行,正则表达式的问题
【发布时间】:2014-02-03 22:17:25
【问题描述】:

大家好,我的数据如下所示

  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/(>\w+)\s([0-9]+)/ ...": 替代模式内未转义的换行符

还有一点需要注意 - 我在 Mac 上执行此操作;我知道 Mac 上的 sedgnu sed 有点不同。如果您能给我提供适用于 Mac 的解决方案,那就太好了。

提前致谢。

【问题讨论】:

  • 你能解释一下“我需要每行200个字符”是什么意思吗,还有其他条件你没有告诉我们吗?
  • 使用“每行 10 个字符”而不是 200 发布一些示例输入和预期输出。您无需了解 200 是如何工作的就能够适应使用10.

标签: regex bash sed awk


【解决方案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 的命令”。

应该为你做得很好。

edit 以防万一您确实需要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 上要求的输出(即使使用额外的回车符来分隔组;如果您不希望这样做,请省略最后两行)。

【讨论】:

  • 嗨,弗洛里斯,我只是试了一下,但它不起作用......文件保持不变
  • @user3049878 我刚刚更新了一个更有用的答案 - 一旦您开始添加额外的计数器等,使用 awk 是正确的方法。它更灵活,更容易理解。跨度>
  • 您好 Floris,我不是使用 awk 的专家,如何设置输入文件???,我尝试了您在终端上输入的内容,但出现语法错误
【解决方案2】:
$ 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 ...

【讨论】:

    【解决方案3】:

    fold是你的朋友:

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

    【讨论】:

      【解决方案4】:

      简单的 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 ...
      

      假设样本名称不包含空格

      【讨论】:

        【解决方案5】:

        在双引号中,反斜杠由 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 将字符串与数字分开,第二个拆分行。

        【讨论】:

        • 谢谢马丁,我会试试的,那么每行 200 个字符呢?你知道怎么做吗?
        • 请解释一下 200 个字符是什么意思,我很乐意为您提供帮助。
        • 嘿马丁,我刚刚尝试了新命令。我没有工作。我得到了和以前完全一样的文件。所以我猜换行有问题??我正在使用 MAC OSX
        • 我的数据实际上有很多 0 和 1。我正在编辑它以在另一个程序中使用它,但是这个新文件每行只能有 200 个字符,所以在第 200 个字符之后我需要换行符和新行中的 201 字符等等
        • 你的意思是200个字符,包括空格(100个数字和100个空格)?
        猜你喜欢
        • 2016-11-02
        • 1970-01-01
        • 2019-08-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-18
        • 2021-12-31
        相关资源
        最近更新 更多