Bash - 在用空格替换新行之前删除破折号和新行

Bash - 在用空格替换新行之前删除破折号和新行

我有一堆以下格式的文本文件:

Lorem ipsum dolor sit amet,
consetetur sadipscing elitr,
sed diam nonumy eirmod tempor
invidunt ut labore et dolore
magna aliquyam erat, sed diam
voluptua. - At vero eos et accu-
sam et justo duo dolores et ea
rebum. - Stet clita kasd guber-
gren, no sea takimata sanctus
est Lorem ipsum dolor sit amet.

如何在命令行上将其打印为连续文本,但删除行末尾的音节分隔:

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. - At vero eos et accusam et justo duo dolores et ea rebum. - Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

我可以用来tr '\n' ' '将换行符转换为空格

问题是tr只能替换一个字符,我需要一些命令来-\n提前删除它。如何在 bash 命令行上实现此目的?

答案1

使用awk

awk -F'-$' '{ printf "%s", sep $1; sep=/-$/?"":OFS } END{ print "" }' infile

-F'-$',我们定义了F产量S分离器到行末尾的单个连字符,因此通过此操作并采用第一个字段$1,对于具有该连字符的行,我们将始终拥有没有该连字符的行,对于那些没有该连字符的行,我们将始终拥有整个行。

然后我们只需用 a 打印它sep之间,但如果当前行以连字符结尾,则读取下一行为空字符串时会发生变化,否则为 OFS (输出F产量S分离器,默认为空格字符)。

END{...}堵塞我们正在添加最后一个换行符来使其POSIX 文本文件,如果您不想添加它,只需删除该部分即可。


使用sed,或者:

sed ':loop /-$/N;s/-\n//;t loop; N;s/\n/ /;t loop' infile
  • :环形
    • 如果一行以连字符结尾(用 测试/-$/),请阅读ext 行并将“连字符+ \newline”替换为空字符串。
      如果替换成功(使用 测试t),则跳转到标签环形并处理下一行并跳过执行其余代码。
    • 否则,请阅读ext 行并\n用空格字符替换这两行之间嵌入的 ewline。
      如果这里替换也成功,则跳转到标签环形并处理下一行。

答案2

另一个perl解决方案(假设最后一行不以-字符结尾):

perl -pe 's/-\n//; s/\n/ / if !eof'

sed与or不同awk,可以使用 直接操作记录分隔符perl。所以,如果匹配的话就很容易删除-\ns/\n/ / if !eof然后将用空格替换剩余的换行符,最后一行除外。

如果您不介意末尾有多余的空格,则可以删除该if !eof部分。

答案3

  1. 删除行末尾用于连字符的破折号(将连字符的行与过程中的下一行连接起来)。
  2. 用空格替换换行符。
sed -e ':again' -e '/[[:alpha:]]-$/ { N; s/-\n//; b again; }' file |
paste -s -d ' ' -

这使用sed连接连字符的行。它通过检测具有破折号且行尾紧接字母的行来实现此目的。通过[[:alpha:]]在破折号前面进行匹配,我更加确定我只是删除了用于连字符的破折号。然后,通过读入下一行 with N(插入文字换行符)并删除-\n.然后重新检查连接的行是否有进一步的连字符(这就是b again标签分支的作用again)。

然后使用该paste实用程序将所有行粘贴到一根连续的行中。该-s选项用于将所有行连接成一行,并-d ' '用于指定连接行时使用的分隔符。

我可以使用tr '\n' ' '它来代替paste我最终得到的命令,但这会给我一个未终止的行(末尾没有换行符)。

答案4

使用POSIX sed流编辑器实用程序。

sed -e ':a
  $!N
  s/-\n//;ta
  s/\n/ /;ta
' file

awk实用程序中,我们设置一个循环来读取下一行并操作 ORS 来打印上一行。

awk '
{
  while (getline t > 0) {
    ORS = sub(/-$/, "") ? "" : OFS
    print
    $0 = t
  }
  ORS = RS
}
1' file

$\我们可以根据当前记录的情况重新排列输出记录分隔符。

perl -lpe '
  $\ =   eof  ? $/
     : s/-$// ? $,
     :          $"
     ;
' file
  • $/是输入记录分隔符,默认为换行符。
  • $"是引号下的数组元素分隔符,默认为空格。
  • $,是输出字段分隔符,默认为空字符串。

相关内容