【问题标题】:Find and replace a new line character and a word in a file using shell使用 shell 查找和替换文件中的换行符和单词
【发布时间】:2021-01-12 12:55:54
【问题描述】:

我有一个文件 sample.txt,其内容是

line-1
Generic-text-1 line-2
Generic-text-2 line-3
line-2
Generic-text-1 line-2
Generic-text-2 line-3

我想将文件的内容更改为 CSV,以便将内容转换为如下所示。

line-1,line-2,line-3
line-2,line-2,line-3

我正在尝试使用 sed 命令,但不适用于换行符。

sed -i 's/\nGeneric-text-1/,/g' sample.txt
sed -i 's/\nGeneric-text-2/,/g' sample.txt

提前致谢

【问题讨论】:

  • awk '$0=$NF' sample.txt | paste -d ',' - - -?
  • 您需要更多详细信息。我们可以猜测“line-1”和“Generic-text-1”之间的区别特征是该行中存在多个非空白字符串,但这只是一个猜测。

标签: shell awk sed scripting


【解决方案1】:

这可能对你有用(GNU sed):

sed -E ':a;$!N;s/\n\S+\s/,/;ta;P;D' file

收集行,用逗号替换换行符、第一个字段及其分隔符。当匹配失败时,打印第一行,删除并重复。

更详细的解释:

  • -E 命令行选项扩展了正则表达式。在这种情况下,允许使用简写 + 而不是 \+
  • :a 是一个占位符 a,它允许在此时恢复执行 sed 命令(稍后与 ta 结合使用)。
  • $!N 只要当前行不是文件$! 中的最后一行,就将下一行N 追加到模式空间中的当前行。模式空间是执行 sed 命令的缓冲区。
  • s/\n\S+\s/,/ 是替换命令,其中 , 将替换为匹配的换行符,后跟一个或多个非空白字符,后跟一个空白字符,即附加行开头的单词,后跟一个至少一个空格。
  • ta 如果替换成功则将代码执行跳转到占位符 a 即返回 2 条指令。
  • P 此时最后一次替换失败,这会打印到并包括模式空间中的第一个换行符。
  • D 这将删除模式空间中的第一个换行符(包括第一个换行符)。但是,与 d 命令重新启动 sed 循环并将下一行读入模式空间不同,此命令仅在当前模式空间为空时才会这样做。如果它包含值,它会在第一个 sed 命令处恢复,在这种情况下是在命令 :a

因此 sed 程序会蚕食文件,创建和打印/删除自己制作的行。

或者在紧要关头:

sed -z 's/\n\S\+ /,/g' file

或:

awk '{gsub(/\n\S+ /,",")}1' RS= file

【讨论】:

  • 如果您能向我解释您给出的第一个解决方案的选项,我将不胜感激:) sed -E ':a;$!N;s/\n\S+\s/, /;ta;P;D' 文件
  • 非常感谢,非常感谢。
【解决方案2】:

使用awk,你可以这样做:

awk -v OFS=, 'NF > 1 {
   printf "%s", OFS $NF
}
NF == 1 {
   if (NR>1)
      print ""
   printf "%s", $1
}
END {
   print ""
}' file
line-1,line-2,line-3
line-2,line-2,line-3

【讨论】:

    【解决方案3】:

    您能否尝试在 GNU awk 中使用所示示例进行跟踪、编写和测试。

    awk '
    BEGIN{ OFS="," }
    /^line/{
      if(val){
        print val
      }
      val=$1
      next
    }
    {
      val=(val?val OFS:"")$NF
    }
    END{
      if(val){
         print val
      }
    }' Input_file
    

    【讨论】:

      【解决方案4】:

      使用awk,只打印每行的最后一个单词。使用逗号分隔符合并成一行,将两个单词行之间的所有单词。

      awk 'NF==1 && NR!=1{print r; r=""} {r = (r? r "," $NF: $NF)} END {print r}' file
      

      输出:

      line-1,line-2,line-3
      line-2,line-2,line-3
      

      【讨论】:

        最近更新 更多