【问题标题】:Editing text in Bash在 Bash 中编辑文本
【发布时间】:2021-03-13 21:02:39
【问题描述】:

我正在尝试在 Bash 中编辑文本,我必须指出我无法继续并且需要帮助。

我需要编辑的文本:

Symbol  Name    Sector  Market Cap, $K  Last    Links
 AAPL
Apple Inc
Computers and Technology
2,006,722,560
118.03
 AMGN
Amgen Inc
Medical
132,594,808
227.76
 AXP
American Express Company
Finance
91,986,280
114.24
 BA
Boeing Company
Aerospace
114,768,960
203.30

我需要的文字:

Symbol,Name,Sector,Market Cap $K,Last,Links
AAPL,Apple Inc,Computers and Technology,2,006,722,560,118.03
AMGN,Amgen Inc,Medical,132,594,808,227.76
AXP,American Express Company,Finance,91,986,280,114.24
BA,Boeing Company,Aerospace,114,768,960,203.30

我已经试过了:

sed 's/$/,/' BIPSukol.txt > BIPSukol1.txt | awk 'NR==1{print}' BIPSukol1.txt | awk '(NR-1)%5{printf "%s ", $0;next;}1' BIPSukol1.txt | sed 's/.$//' 

但它并没有完全完成这项工作。 (BIPSukol1.txt 是我正在编辑的文件名)

【问题讨论】:

  • 第一行总是一样的吗?
  • 我投票结束这个问题,因为我和其他人大约一周前在 unix.stackexchange.com/q/621160/133219 回答了同样的问题。
  • @Cyrus -- 你作弊了 -- 但我喜欢 :)。当/如果您取消删除时,请发表评论。分两行做,值得紫外线。
  • @Ed Morton 对不起,我没有意识到有人问同样的问题。它实际上是大学任务,我想我不是唯一一个在这里问的人,我会删除帖子,给我几分钟:)
  • Grollda,这就是为什么现在鼓励您使用搜索功能来完成您的任务,因为您可以使用老师可以抓住的答案 :) :) (轻点)您可以使用此线程这些不同的答案。我不确定这个关于 SO 的规则可能是@Ed Morton 先生,其他受人尊敬的成员可以指导(如果我不在这里打扰)这个(如果有办法从我所在的另一个站点进行欺骗)不知道诚实)欢呼。

标签: bash file awk text sed


【解决方案1】:

您遇到的最大问题是您的字段之间没有一致的分隔符。有些有逗号,有些没有,有些只是碰巧一起运行的 3 个字段的组合。

您想要的工具是awk。它将允许您以不同的方式处理第一行,然后使用您保留在脚本中的方便的计数器来调节后面的输出。在awk 中,您编写rules(外部{...}awk 之间的内容按照它们编写的顺序应用您的规则。这允许您“修复”您的情况危险格式并达到所需的输出。

应用的第一条规则FNR==1 应用于第一行。它遍历字段并找到有问题的"Market Cap $K" 字段并将其视为一个,跳过它以输出剩余的标题。它存储一个计数器count = NF - 3,因为每个符号只有 5 行数据,然后跳到下一条记录。

count==n 触发下一条规则,该规则仅输出存储在a[] 数组中的记录,将count 归零并删除a[] 数组以进行重新填充。

下一条规则适用于从第 2 次开始输入的每条记录(行)。它通过强制awk 重新计算具有$1 = $1 的字段来简单地从字段中删除任何whitespece,然后将记录存储在递增count 的数组中。

最后一条规则,END 是一个特殊规则,它在处理完所有记录后运行(它可以让您汇总最终计数或输出最后的数据行)这里它用于输出保留在a[] 中的记录时已到达文件末尾。

把它放在另一个剪辑中awk

awk '
    FNR==1 {
        for (i=1;i<=NF;i++)
            if ($i == "Market") {
                printf ",Market Cap $K"
                i = i + 2
            }
            else
                printf (i>1?",%s":"%s"), $i
        print ""
        n = NF-3
        count = 0
        next
    }
    count==n {
        for (i=1;i<=n;i++)
            printf (i>1?",%s":"%s"), a[i]
        print ""
        delete a
        count = 0
    }
    {
        $1 = $1
        a[++count] = $0
    }
    END {
        for (i=1;i<=count;i++)
            printf (i>1?",%s":"%s"), a[i]
        print ""
    }
' file

使用/输出示例

注意:您可以简单地选择-复制上面的脚本,然后用鼠标中键将其粘贴到具有目录集的 xterm 中,以便它包含 file(您需要将 file 重命名为您的输入文件名)

$ awk '
>     FNR==1 {
>         for (i=1;i<=NF;i++)
>             if ($i == "Market") {
>                 printf ",Market Cap $K"
>                 i = i + 2
>             }
>             else
>                 printf (i>1?",%s":"%s"), $i
>         print ""
>         n = NF-3
>         count = 0
>         next
>     }
>     count==n {
>         for (i=1;i<=n;i++)
>             printf (i>1?",%s":"%s"), a[i]
>         print ""
>         delete a
>         count = 0
>     }
>     {
>         $1 = $1
>         a[++count] = $0
>     }
>     END {
>         for (i=1;i<=count;i++)
>             printf (i>1?",%s":"%s"), a[i]
>         print ""
>     }
> ' file
Symbol,Name,Sector,Market Cap $K,Last,Links
AAPL,Apple Inc,Computers and Technology,2,006,722,560,118.03
AMGN,Amgen Inc,Medical,132,594,808,227.76
AXP,American Express Company,Finance,91,986,280,114.24
BA,Boeing Company,Aerospace,114,768,960,203.30

注意:不清楚为什么要包含 "Links" 标题,因为该字段没有信息 - 但这是指定所需输出的方式)

更高效的无数组

在你发布答案后,你总会有一些事后的想法,这与在考试结束时记住一个更好的回答问题的方法没有什么不同,或者在思考你希望在之后提出的另一个问题您为证人辩解或在审判中停止您的案件。 (有一首歌捕捉到了它——有点讽刺:)

下面的内容基本相同,但不使用数组。相反,它只是在格式化信息后输出信息,而不是将其缓冲在一个数组中以便一次全部输出。这是一种事后的想法:

awk '
    FNR==1 {
        for (i=1;i<=NF;i++)
            if ($i == "Market") {
                printf ",Market Cap $K"
                i = i + 2
            }
            else
                printf (i>1?",%s":"%s"), $i
        print ""
        n = NF-3
        count = 0
        next
    }
    count==n {
        print ""
        count = 0
    }
    {
        $1 = $1
        printf (++count>1?",%s":"%s"), $0
    }
    END { print "" }
' file

(相同的输出)

【讨论】:

    【解决方案2】:

    对于您展示的示例,您能否尝试以下操作(使用 GNU awk 编写和测试)。考虑到(通过查看 OP 的尝试)您希望在 Input_file 的标题之后将每 5 行变成一行。

    awk '
    BEGIN{
      OFS=","
    }
    FNR==1{
      NF--
      match($0,/Market.*\$K/)
      matchedPart=substr($0,RSTART,RLENGTH)
      firstPart=substr($0,1,RSTART-1)
      lastPart=substr($0,RSTART+RLENGTH)
      gsub(/,/,"",matchedPart)
      gsub(/ +/,",",firstPart)
      gsub(/ +/,",",lastPart)
      print firstPart matchedPart lastPart
      next
    }
    {
      sub(/^ +/,"")
    }
    ++count==5{
      print val,$0
      count=0
      val=""
      next
    }
    {
      val=(val?val OFS:"")$0
    }
    '  Input_file
    


    或者,如果您的 awk 不支持 NF--,请尝试关注。

    awk '
    BEGIN{
      OFS=","
    }
    FNR==1{
      match($0,/Market.*\$K/)
      matchedPart=substr($0,RSTART,RLENGTH)
      firstPart=substr($0,1,RSTART-1)
      lastPart=substr($0,RSTART+RLENGTH)
      gsub(/,/,"",matchedPart)
      gsub(/ +/,",",firstPart)
      gsub(/ +Links( +)?$/,"",lastPart)
      gsub(/ +/,",",lastPart)
      print firstPart matchedPart lastPart
      next
    }
    {
      sub(/^ +/,"")
    }
    ++count==5{
      print val,$0
      count=0
      val=""
      next
    }
    {
      val=(val?val OFS:"")$0
    }
    ' Input_file
    

    注意: 看起来您的标题/第一行需要特殊处理,因为我们不能简单地将 , 设置为所有空格,所以在此注意根据所示示例解决方案。

    【讨论】:

    • 您的代码几乎可以工作,唯一的问题是您的解决方案中的第一行逗号太多您的解决方案:Symbol,Name,Sector,Market,Cap,,$K,Last,Link 我需要什么:'Symbol,Name,Sector,Market Cap $K,Last,Links
    • @Grolldash,已经处理好了,请检查我编辑的解决方案一次 :) 然后让我知道。
    • 很抱歉打扰了,Cap 之后还有一个逗号我只是注意到在第一行我还需要删除单词Links 和它之前的逗号
    • @Grolldash,没问题,现在已经修复好了,请告诉我它是怎么回事(删除我在这里使用的NF-- 并用 GNU awk 测试过的链接)?跨度>
    • 仍有一些事情不是它应该的样子。我会尝试自己找到问题,所以我不会打扰你。如果我找到解决方案,我会在此处发布 :) 感谢您为我设置正确的方法! :)
    【解决方案3】:

    使用 GNU awk。如果你的第一行总是一样的。

    echo 'Symbol,Name,Sector,Market Cap $K,Last,Links'
    awk 'NR>1 && NF=5' RS='\n ' ORS='\n' FS='\n' OFS=',' file
    

    输出:

    代码、名称、部门、市值 $K、姓氏、链接 AAPL,苹果公司,计算机和技术,2,006,722,560,118.03 AMGN,安进公司,医疗,132,594,808,227.76 AXP,美国运通公司,金融,91,986,280,114.24 BA,波音公司,航空航天,114,768,960,203.30

    见:8 Powerful Awk Built-in Variables – FS, OFS, RS, ORS, NR, NF, FILENAME, FNR

    【讨论】:

    • 是的,每次看到这样的答案时,我总是会重新学习如何充分使用内置插件。少打字:)
    猜你喜欢
    • 2019-12-31
    • 2017-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多