【问题标题】:Turning multi-line string into single comma-separated将多行字符串转换为单个逗号分隔
【发布时间】:2012-02-01 14:46:58
【问题描述】:

假设我有以下字符串:

something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)

我如何把它变成简单的

+12.0,+15.5,+9.0,+13.5

在 bash 中?

【问题讨论】:

  • 让我们退后一步,考虑一下这个线程是对 bash 作为编程语言的明显控诉。考虑 Scala 的 listOfStuff mkString ", " 或 Haskell 的 intercalate ", " listOfString

标签: string bash shell csv


【解决方案1】:

另一个 AWK 解决方案

运行

awk '{printf "%s", $c; while(getline){printf "%s%s", sep, $c}}' c=2 sep=','

使用第 2 列形成以逗号分隔的列表。像往常一样在标准输入中或作为文件名参数提供输入。

【讨论】:

    【解决方案2】:

    试试这个简单的代码:

    awk '{printf("%s,",$2)}' File1
    

    【讨论】:

    • 它添加了一个额外的逗号
    【解决方案3】:

    这可能对你有用:

    cut -d' ' -f5 file | paste -d',' -s
    +12.0,+15.5,+9.0,+13.5
    

    sed '/^.*\(+[^ ]*\).*/{s//\1/;H};${x;s/\n/,/g;s/.//p};d' file
    +12.0,+15.5,+9.0,+13.5
    

    sed 's/\S\+\s\+//;s/\s.*//;H;$!d;x;s/.//;s/\n/,/g' file
    

    对于文件中的每一行;砍掉第一个字段和后面的空格,砍掉第二个字段后面的行的其余部分并附加到保留空间。删除除我们交换到保留空间的最后一行之外的所有行,并在删除开头引入的换行符后,将所有换行符转换为,'s。

    注意可以写成:

    sed 's/\S\+\s\+//;s/\s.*//;1h;1!H;$!d;x;s/\n/,/g' file
    

    【讨论】:

      【解决方案4】:

      干净简单:

      awk '{print $2}' file.txt | paste -s -d, -
      

      【讨论】:

      • 这是最好的答案,显然是正确的方法
      • 如何用单/双引号引用每个值?
      • @Hussain cat thing | awk -F',' '{ print "'\''" $7 "'\' '" }' | paste -s -d ','
      • 如何使用,'作为分隔符?
      • 如果字符串中有任何 CRLF,请记住处理 Windows 换行符(例如使用dos2unix)。
      【解决方案5】:

      好吧,最难的部分可能是选择第二个“列”,因为我不知道有一种简单的方法可以将多个空格视为一个空格。其余的很容易。使用 bash 替换。

      # cat bla.txt
      something1:    +12.0   (some unnecessary trailing data (this must go))
      something2:    +15.5   (some more unnecessary trailing data)
      something4:    +9.0   (some other unnecessary data)
      something1:    +13.5  (blah blah blah)
      
      # cat bla.sh
      OLDIFS=$IFS
      IFS=$'\n'
      for i in $(cat bla.txt); do
        i=$(echo "$i" | awk '{print $2}')
        u="${u:+$u, }$i"
      done
      IFS=$OLDIFS
      echo "$u"
      
      # bash ./bla.sh
      +12.0, +15.5, +9.0, +13.5
      

      【讨论】:

        【解决方案6】:

        awk 一个班轮

        $ awk '{printf (NR>1?",":"") $2}' file
        
        +12.0,+15.5,+9.0,+13.5
        

        【讨论】:

        • 格式说明符"%s", 应该在printf 之后添加以使其更健壮,即使其适用于所有类型的行,例如“foo %s”。
        【解决方案7】:

        没有看到这个简单的 awk 解决方案

        awk 'b{b=b","}{b=b$2}END{print b}' infile
        

        【讨论】:

          【解决方案8】:
          cat data.txt | xargs | sed -e 's/ /, /g'
          

          【讨论】:

          • 我也喜欢这样的解决方案,但这里是否需要 -e arg,因为只有第一个命令用于 sed?我相信cat data.txt | xargs | sed 's/ /, /g' 会一样工作。例如,echo -e "foo\nbar\nbazz" | xargs | sed 's/ /, /g' 输出 foo, bar, bazz
          【解决方案9】:

          用纯 Bash 编写的解决方案:

          #!/bin/bash
          
          sometext="something1:    +12.0   (some unnecessary trailing data (this must go))
          something2:    +15.5   (some more unnecessary trailing data)
          something4:    +9.0   (some other unnecessary data)
          something1:    +13.5  (blah blah blah)"
          
          a=()
          while read -r a1 a2 a3; do
              # we can add some code here to check valid values or modify them
              a+=("${a2}")
          done <<< "${sometext}"
          # between parenthesis to modify IFS for the current statement only
          (IFS=',' ; printf '%s: %s\n' "Result" "${a[*]}")
          

          结果:+12.0,+15.5,+9.0,+13.5

          【讨论】:

          • 您也可以使用read -r -a cols,然后将"${cols[1]} 添加到列表a
          【解决方案10】:

          你可以使用grep:

          grep -o "+\S\+" in.txt | tr '\n' ','
          

          查找以+ 开头的字符串,后跟任何字符串\S\+,然后将换行符转换为逗号。对于大文件,这应该很快。

          【讨论】:

            【解决方案11】:

            另一个 Perl 解决方案,类似于 Dan Fego 的 awk:

            perl -ane 'print "$F[1],"' file.txt | sed 's/,$/\n/'
            

            -a 告诉 perl 将输入行拆分为 @F 数组,该数组从 0 开始索引。

            【讨论】:

              【解决方案12】:

              试试这个:

              sedSelectNumbers='s".* \(+[0-9]*[.][0-9]*\) .*"\1,"'
              sedClearLastComma='s"\(.*\),$"\1"'
              cat file.txt |sed "$sedSelectNumbers" |tr -d "\n" |sed "$sedClearLastComma"
              

              好消息是删除换行符“\n”字符很容易!

              编辑:使用 sed 将行合并为一行的另一种好方法是:|sed ':a;N;$!ba;s/\n/ /g' got from here

              【讨论】:

              • 那个编辑很棒 - +1!
              【解决方案13】:

              你也可以这样打印:

              只是 awk:使用 printf

              bash-3.2$ cat sample.log
              something1:    +12.0   (some unnecessary trailing data (this must go))
              something2:    +15.5   (some more unnecessary trailing data)
              something4:    +9.0   (some other unnecessary data)
              something1:    +13.5  (blah blah blah)
              
              bash-3.2$ awk ' { if($2 != "") { if(NR==1) { printf $2 } else { printf "," $2 } } }' sample.log
              +12.0,+15.5,+9.0,+13.5
              

              【讨论】:

                【解决方案14】:

                这应该也可以

                awk '{print $2}' file | sed ':a;{N;s/\n/,/};ba'
                

                【讨论】:

                  【解决方案15】:
                  $ awk -v ORS=, '{print $2}' data.txt | sed 's/,$//'
                  +12.0,+15.5,+9.0,+13.5
                  

                  $ cat data.txt | tr -s ' ' | cut -d ' ' -f 2 | tr '\n' ',' | sed 's/,$//'
                  +12.0,+15.5,+9.0,+13.5
                  

                  【讨论】:

                  • 干杯,如果 awk 的输入是通过标准输入(只需在您的示例中输入 function | awk...
                  【解决方案16】:

                  你也可以通过两个 sed 调用来做到这一点:

                  $ cat file.txt 
                  something1:    +12.0   (some unnecessary trailing data (this must go))
                  something2:    +15.5   (some more unnecessary trailing data)
                  something4:    +9.0   (some other unnecessary data)
                  something1:    +13.5  (blah blah blah)
                  $ sed 's/^[^:]*: *\([+0-9.]\+\) .*/\1/' file.txt | sed -e :a -e '$!N; s/\n/,/; ta'
                  +12.0,+15.5,+9.0,+13.5
                  

                  第一个 sed 调用删除不感兴趣的数据,第二个加入所有行。

                  【讨论】:

                    【解决方案17】:

                    使用 perl:

                    fg@erwin ~ $ perl -ne 'push @l, (split(/\s+/))[1]; END { print join(",", @l) . "\n" }' <<EOF
                    something1:    +12.0   (some unnecessary trailing data (this must go))
                    something2:    +15.5   (some more unnecessary trailing data)
                    something4:    +9.0   (some other unnecessary data)
                    something1:    +13.5  (blah blah blah)
                    EOF
                    
                    +12.0,+15.5,+9.0,+13.5
                    

                    【讨论】:

                      【解决方案18】:

                      您可以使用awksed

                      awk -vORS=, '{ print $2 }' file.txt | sed 's/,$/\n/'
                      

                      或者如果你想使用管道:

                      echo "data" | awk -vORS=, '{ print $2 }' | sed 's/,$/\n/'
                      

                      分解:

                      • awk 擅长处理细分为字段的数据
                      • -vORS=, 将“输出记录分隔符”设置为 ,,这正是您想要的
                      • { print $2 } 告诉 awk 打印每条记录(行)的第二个字段
                      • file.txt 是你的文件名
                      • sed 只是去掉了尾随的 , 并将其变成一个换行符(如果你不想换行符,你可以这样做 s/,$//

                      【讨论】:

                      • awk: 无效的 -v 选项 :(
                      • 在 -v 和 ORS= 之间添加一个空格,(对我来说,在 osx 上)
                      • 如何执行相同的命令来分离管道? awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/' 遇到错误
                      • 奇怪的是,当我尝试这样做时,输出为空。
                      • 我认为管道版本应该是 {print $1} 否则我在输出中只会得到逗号
                      猜你喜欢
                      • 2016-01-29
                      • 1970-01-01
                      • 1970-01-01
                      • 2021-12-13
                      • 1970-01-01
                      相关资源
                      最近更新 更多