【问题标题】:Printing field that also contains FS character?打印字段也包含 FS 字符?
【发布时间】:2020-11-12 04:03:11
【问题描述】:

要在 AWK 中处理的记录有以下可能的格式:

foobar是定长,serialno是变长,我要抓取的字段可能包含零个或多个下划线。

foobar_823932230_processname.txt
foobar_82393280_process_name.txt
foobar_8239330_foo_process_name.txt

期望的输出

processname
process_name
foo_process_name

如果我使用FS="[_.]",那么我可以使用print $3,它适用于第一条记录,但不适用于第二条和第三条。

如何捕获序列号和 .txt 之间的所有内容?

我正在编辑需要更改的旧版 AWK 代码。一旦我正确捕获了这个字段,awk 进程就会继续生成额外的输出。

【问题讨论】:

  • 使用 GNU sed 的单行代码:sed -E 's/^([^_]*_){2}//; s/\.[^.]*$//' file

标签: regex awk sed cut


【解决方案1】:

这个cut + cut 也应该可以工作:

cut -d_ -f3- file | cut -d. -f1
processname
process_name
foo_process_name

awk 解决方案将使用此正则表达式:

awk '{gsub(/^([^_]+_){2}|\..*$/, "")} 1' file

【讨论】:

    【解决方案2】:

    您似乎需要调整现有的 awk 脚本以适应此要求。可惜 awk 没有 join 函数,但我们可以自己滚动:

    function join_fields(from, to, joiner,     result, i, sep) {
      for (i=from; i<=to; i++) {
        result = result sep $i
        sep = joiner
      }
      return result
    }
    

    演示:

    awk -F '[_.]' '
      function join_fields(from, to, joiner,     result, i, sep) {
        for (i=from; i<=to; i++) {
          result = result sep $i
          sep = joiner
        }
        return result
      }
    
      {
          field = join_fields(3, NF-1, "_")
          print $0, "\t", field
      }
    ' <<END
    foobar_823932230_processname.txt
    foobar_82393280_process_name.txt
    foobar_8239330_foo_process_name.txt
    END
    
    foobar_823932230_processname.txt     processname
    foobar_82393280_process_name.txt     process_name
    foobar_8239330_foo_process_name.txt      foo_process_name
    

    【讨论】:

    • ++ 真的好用join_fields函数
    【解决方案3】:

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

    awk 'match($0,/.*[0-9]+_/){print substr($0,RSTART+RLENGTH)}'  Input_file
    

    【讨论】:

      【解决方案4】:

      使用

      $ awk 'BEGIN{FS="[[:digit:]]+_"} {gsub(/\..+$/,"", $2); print $2}' file
      processname
      process_name
      foo_process_name
      

      这可以通过将字段分隔符 FS 设置为数字后跟 _,并通过使用 gsub 剥离文件扩展名的结果变量 $2 来实现

      【讨论】:

        【解决方案5】:

        使用具有-E 的 sed 来启用 ERE(例如 GNU sed 和 BSD/OSX sed):

        $ sed -E 's/([^_]+_){2}(.*)\.txt$/\2/' file
        processname
        process_name
        foo_process_name
        

        使用任何 POSIX sed:

        $ sed 's/\([^_]\{1,\}_\)\{2\}\(.*\)\.txt$/\2/' file
        processname
        process_name
        foo_process_name
        

        使用 GNU awk:

        $ awk '{$0=gensub(/([^_]+_){2}(.*)\.txt$/,"\\2",1)} 1' file
        processname
        process_name
        foo_process_name
        

        使用任何 awk:

        $ awk '{sub(/([^_]+_){2}/,""); sub(/\.txt$/,"")} 1' file
        processname
        process_name
        foo_process_name
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-06-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多