【问题标题】:Deleting a word from a string从字符串中删除一个单词
【发布时间】:2017-07-17 13:28:07
【问题描述】:

我想从文件中删除特定的单词。

假设文件名agent_file.txt 包含以下字符串

-queues winall,dustat,envstat,netstat,iostat,winconfig,netwarestat,netwareconfig,pawmin,paw15,db2,sqlserver,vmstatvmw2,vmstatvm2,netstatvm,netstatvmw,vmstatvm,vmstatvmw,iostatvm,iostatvmw,envstatvm,envstatvmw,vmscpu,vmsdisk,vmsmem,vmstatvcw,process,winprocess

我只想删除这个文件中的字符或单词process,所以我在Unix下使用下面的命令

perl -pi -e 's/process//g' agent_file.txt

输出将是

-queues winall,dustat,envstat,netstat,iostat,winconfig,netwarestat,netwareconfig,pawmin,paw15,db2,sqlserver,vmstatvmw2,vmstatvm2,netstatvm,netstatvmw,vmstatvm,vmstatvmw,iostatvm,iostatvmw,envstatvm,envstatvmw,vmscpu,vmsdisk,vmsmem,vmstatvcw,,win

这个词被删除了,但同时也删除了winprocess的一部分。

如何只删除process 以及前面的逗号,(如果有的话)?

输出应该是

-queues winall,dustat,envstat,netstat,iostat,winconfig,netwarestat,netwareconfig,pawmin,paw15,db2,sqlserver,vmstatvmw2,vmstatvm2,netstatvm,netstatvmw,vmstatvm,vmstatvmw,iostatvm,iostatvmw,envstatvm,envstatvmw,vmscpu,vmsdisk,vmsmem,vmstatvcw,winprocess

【问题讨论】:

    标签: regex perl awk sed ksh


    【解决方案1】:

    这是一个awk 解决方案。

    awk 'BEGIN{OFS=FS=","} {for(i=1;i<=NF;i++) if($i=="process") $i=""} 1' file
    

    这会将您的字段分隔符设置为输入和输出的逗号,然后逐步检查您的字段,检查您感兴趣的字符串是否等价,如果匹配则清空该字段。末尾的 1 是“打印当前行”的 awk 简写。


    同样,可以按记录而不是按字段对输入数据进行切片:

    awk 'BEGIN{ORS=RS=","} /^process$/{next} 1' file
    

    awk 'BEGIN{ORS=RS=","} $0=="process"{next} 1' file
    

    这将使用逗号作为 RECORD 分隔符 (RS) 遍历您的输入,以便可以使用 awk 的记录感知来评估单个单词。您可以通过或不通过正则表达式进行评估 - 正则表达式稍微慢一些,但似乎可以为您节省两个打字字符。 :-)

    使用 RS/ORS 的策略消除了您注意到的字段被清空但未删除的问题。当逗号是记录分隔符时,跳过的记录会导致不显示记录分隔符,这更接近您在问题中包含的“理想”输出。


    最后一个选项可能是在您的 shell (ksh) 中执行此操作。这将具有最大的可移植性优势(您不必担心 perl 版本,无论 awk/sed 是 GNU 还是 BSD 或其他)。缺点是使用下面的方法,您的文件大小将受到系统内存的限制(可能还有可配置的限制)。

    $ IFS=, read -A arr < file
    $ for i in "${!arr[@]}"; do [[ "${arr[$i]}" == "process" ]] && unset arr[$i]; done
    $ output=$(printf "%s," "${arr[@]}")
    $ echo "${output%,}"
    -queues winall,dustat,envstat,netstat,iostat,winconfig,netwarestat,netwareconfig,pawmin,paw15,db2,sqlserver,vmstatvmw2,vmstatvm2,netstatvm,netstatvmw,vmstatvm,vmstatvmw,iostatvm,iostatvmw,envstatvm,envstatvmw,vmscpu,vmsdisk,vmsmem,vmstatvcw,winprocess
    

    请注意,$output 变量仅用于去除printf 生成的尾随逗号。另一种选择可能是更全局地设置$IFS

    $ IFS=,
    $ echo "${arr[*]}"
    -queues winall,dustat,envstat,netstat,iostat,winconfig,netwarestat,netwareconfig,pawmin,paw15,db2,sqlserver,vmstatvmw2,vmstatvm2,netstatvm,netstatvmw,vmstatvm,vmstatvmw,iostatvm,iostatvmw,envstatvm,envstatvmw,vmscpu,vmsdisk,vmsmem,vmstatvcw,winprocess
    

    我应该指出,尽管看起来,printf 选项并没有真正产生外部命令,因为 ksh 将 printf 实现为内置的。

    【讨论】:

      【解决方案2】:

      通过逗号 (-F,) 使用自动拆分 (-a),完全避免逗号问题

      perl -F, -lane 'print join ",", grep { not /^process$/ } @F' input  > output
      

      输入被, 分解为@Fgrep 过滤掉这个词,其余的由, 加入

      为了更改输入文件,添加-i并删除&gt; output

      Command switches in perlrun


      问题是第一个和最后一个单词有一个逗号,如果删除它们就需要去,而其他单词有两个逗号需要留下。使用正则表达式的一种方法是进行两次传递,删除单词,然后删除额外的逗号(仍然要小心第一个和最后一个)。

      或在替换部分中运行代码以选择案例适当的

      echo "go,stay,ago,go,got,end,go" | 
      
          perl -pe's/(,)?\bgo\b(,)?/$1 && $2 && ","/ge'
      

      打印:stay,ago,got,end/e 将替换端评估为 Perl 代码。

      如果两个逗号都存在 ($1 &amp;&amp; $2) 则 (&amp;&amp;) 我们用逗号 (",") 替换。

      这是因为在 Perl &amp;&amp; returns the value

      ||//&amp;&amp; 运算符返回最后评估的值(与 C 的 ||&amp;&amp; 不同,它们返回 0 或 1)。

      【讨论】:

        【解决方案3】:

        如果它是逗号分隔的,请使用它们来使其成为一个单词。

        perl -pi -e "s/, \s* process\s* , /, /g filename 
        

        如果逗号前后没有空格,则删除 \s*

        【讨论】:

          【解决方案4】:

          也许像这样?

          它会搜索所有出现的process,使用单词边界来确保它不是作为另一个单词的一部分,并且还匹配前后的可选逗号,。如果找到两个逗号(在列表中间找到process),则匹配由一个逗号替换,如果只有一个(process 仅出现在列表的开头或结尾),则将其删除

          perl -pi -e 's/ ,? \b process \b ,? ) / $1 =~ tr/,// > 1 ? ',' : '' /xge' agent_file.txt
          

          【讨论】:

            【解决方案5】:

            你可以分三步完成

            sed 's/,process,/,/g;s/^process,//;s/,process$//'   
            

            测试位置,:中间,开始或结束。

            【讨论】:

            • \b 似乎是 GNU-only。此解决方案不适用于 OS X 或 *BSD。
            • 感谢@karakfa,这很有帮助,但这仅适用于 GNU sed...但不适用于我在 AIX 下的 sed...=(
            • 如果process 出现在列表的开头或结尾,这不会删除多余的前导或尾随逗号。
            【解决方案6】:
            awk '{sub(/process,/,"")}1' file
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-11-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多