AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 674572
Accepted
Renga
Renga
Asked: 2021-10-24 22:12:21 +0800 CST2021-10-24 22:12:21 +0800 CST 2021-10-24 22:12:21 +0800 CST

从文件传递时变量在 awk 中不接受

  • 772

我正在逐行读取文件。每行如下所示:

xxyu: JHYU_IOPI

每一行都传递给 awk,如下所示。我想打印匹配模式的上一行;我可以使用 grep 来实现这一点,并且想知道我在 awk 中犯了什么错误。

#!/bin/bash
while read i
do
 awk '/$i/{print a}{a=$0}' ver_in.txt
done<in.txt

我也试过这个:

#!/bin/bash
while read i
do
 awk -v var="$i" '/var/{print a}{a=$0}' jil.txt
done<in.txt

编辑:在得到不使用 sh read 的建议后使用 awk。我的输入和所需的输出如下所示:

编辑1:编辑@Ed Morton awk 脚本的输入,如下所示

输入文件:cat文件

/* ----------------- AIX_RUN_WATCH ----------------- */ 

insert_job: AIX_RUN_WATCH   job_type: BOX 
owner: root
permission: 
date_conditions: 1
days_of_week: su
start_times: "22:00"
alarm_if_fail: 1
alarm_if_terminated: 1
group: app
send_notification: 0
notification_emailaddress: 


 /* ----------------- AIX_stop ----------------- */ 

 insert_job: AIXstop   job_type: CMD 
 box_name: AIX_RUN_WATCH
 command: ls
 machine: cfg.mc
 owner: root
 permission: 
 date_conditions: 0
 box_terminator: 1
 std_out_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stdout"
 std_err_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stderr"
 alarm_if_fail: 1
 alarm_if_terminated: 1
 group: app
 send_notification: 1


 /* ----------------- AIX_start ----------------- */ 

 insert_job: AIX_start   job_type: CMD 
 box_name: AIX_RUN_WATCH
 command: ls
 machine: cfg.mc
 owner: root
 permission: 
 date_conditions: 0
 box_terminator: 1
 std_out_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stdout"
 std_err_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stderr"
 alarm_if_fail: 1
 alarm_if_terminated: 1
 group: app

   cat targets
     box_name: AIX_RUN_WATCH

预期产出 -

 box_name: AIX_RUN_WATCH
 insert_job: AIX_stop
 insert_job: AIX_start
awk text-processing
  • 3 3 个回答
  • 899 Views

3 个回答

  • Voted
  1. αғsнιη
    2021-10-24T22:54:39+08:002021-10-24T22:54:39+08:00

    对于第一次尝试,您需要使用双引号进行 shell 变量扩展,然后转义 awk$运算符以防止其被 shell 扩展,但请注意,如果变量$i包含特殊字符(如\, ),这样使用会破坏 awk /。[我现在跳过修复您的命令的一个或多个其他问题]。

    while read i
    do
     awk "/$i/{print a}{a=\$0}" ver_in.txt
    done<in.txt
    

    对于第二次尝试,您需要对当前行使用正则表达式匹配或字符串匹配,例如使用正则表达式匹配(部分正则表达式匹配):

    while read i
    do
     awk -v var="$i" '$0 ~ var{print a}{a=$0}' jil.txt
    done<in.txt
    

    或字符串匹配(完整字符串匹配),例如:

    while read i
    do
     awk -v var="$i" '$0==var{print a}{a=$0}' jil.txt
    done<in.txt
    

    现在,谈论您尝试使用它们打印匹配模式的前一行的命令,您可以使用 awk 完成所有操作并使用 shell 循环停止;这里我们进行全字符串匹配:

    awk 'NR==FNR { str[$0]; next }
    ($0 in str) && prev!="" { print prev } { prev=$0 }' in.txt ver_in.txt
    

    或进行部分正则表达式匹配:

    awk 'NR==FNR { patt[$0]; next }
    { for(ptrn in patt) if($0 ~ ptrn && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
    

    或进行部分字符串匹配:

    awk 'NR==FNR { strings[$0]; next }
    { for(str in strings) if(index($0, str) && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
    

    或进行完整的正则表达式匹配:

    awk 'NR==FNR { patt[$0]; next }
    { for(ptrn in patt) if($0 ~ "^"ptrn"$" && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
    
    • 7
  2. cas
    2021-10-24T22:44:53+08:002021-10-24T22:44:53+08:00

    您不需要 while read 循环,并且在 sh 中进行文本处理是一个坏主意(请参阅为什么使用 shell 循环处理文本被认为是不好的做法?)。

    而是让您的 awk 脚本来处理这两个文件。

    awk 'NR==FNR { re = $0 "|" re ; next}; # append input line and | to re
         FNR == 1 { sub(/\|$/,"",re) };    # remove trailing | on 1st line of 2nd file
    
         $0 ~ re { print a }; # if the current line matches re, print a
         {a = $0}' in.txt ver_in.txt
    

    在读取第一个文件 ( in.txt) 时,它在一个变量中构建一个正则表达式,该变量re通过附加每个输入行和正则表达式“交替”(即OR)运算符来调用。

    当它读完第一个文件后,它需要做的第一件事就是|从re. 这是必要的,因为由于它的构造方式,它re总是以字符结尾。|如果我们不删除它,那么尾随|将导致正则表达式匹配ver_in.txt.

    之后,a如果当前输入行与变量中的正则表达式匹配,则打印变量re(如果 ver_in.txt 的第一行匹配,这将打印一个空行re- 因为 a 是空的。如果您不希望发生这种情况,请将该行从$0 ~ re {print a}到$0 ~ re && a != "" {print a})。

    然后,无论是否匹配,设置a=$0.

    注意:这NR==FNR {... ; next}是一个非常常见的 awk 习惯用法,用于以与第二个和后续输入文件不同的方式处理第一个输入文件。 NR是正在读取的所有文件的全局行计数器,并且FNR是当前文件的行计数器....所以如果NR==FNR,这意味着我们正在读取第一个文件。该next语句跳到下一个输入行,防止在第一个文件中执行 awk 脚本的其余部分。

    你没有提供完整的数据样本,所以我自己做了一个测试:

    $ cat in.txt 
    xxyu: JHYU_IOPI
    foo
    bar
    

    这个 in.txt 文件将导致 re 等于bar|foo|xxyu: JHYU_IOPI

    顺便说一句,因为 awk 脚本正在对 进行正则表达式匹配re,所以中的行in.txt被视为正则表达式,而不是固定文本。这意味着,如果您希望将 in.txt 中的任何正则表达式特殊字符(如、.或许多其他字符)视为文字字符,则需要使用反斜杠对其进行转义......您必须这样做这也与您原来的 sh+awk 循环一起使用。|[]

    $ cat ver_in.txt 
    a line 1
    xxyu: JHYU_IOPI
    b line 3
    d line 4
    bar
    e line 6
    f line 7
    foo
    

    上面 awk 脚本的输出:

    a line 1
    d line 4
    f line 7
    
    • 3
  3. Best Answer
    Ed Morton
    2021-10-26T05:23:35+08:002021-10-26T05:23:35+08:00

    不要使用 shell 循环来操作文本,请参阅为什么使用 shell 循环来处理文本被认为是不好的做法?. 发明 shell 的人还发明了 awk 让 shell 调用来操作文本。

    在每个 Unix 机器上的任何 shell 中使用任何 awk:

    $ cat tst.awk
    NR==FNR {
        tgts[$0]
        next
    }
    $0 in tgts {
        if ( $0 != prevTgt ) {
            print $0
            prevTgt = $0
        }
        print prevLine
    }
    { prevLine = $1 FS $2 }
    

    $ awk -f tst.awk targets file
    box_name: AIX_RUN_WATCH
    insert_job: AIXstop
    insert_job: AIX_start
    

    原答案:

    awk '
        BEGIN { RS=""; FS="\n" }
        $2 != prev {
            print $2
            prev = $2
        }
        { print $1 }
    ' file
    ght: ertyjk
    xxx: rtyuiol
    xxx: ertyuikl_fghjk
    xxx: qwertyujkl
    xxx: rtyuiol_123
    ght: YUIOPO
    xxx: rtyuiol
    xxx: rtyuiopfghj
    xxx: dfghjkvbnm
    xxx: qzdfghnbvfgh
    xxx: qsxcvghuiokmnhgf
    

    请参阅https://www.gnu.org/software/gawk/manual/gawk.html#Multiple-Line了解如何将 RS 设置为 null 让我们处理多行记录,然后将 FS 设置为换行符意味着中的每个字段这样的记录是一整行,因此我们将您的数据视为以空行分隔的记录,每条记录包含 2 行数据。

    You mentioned having some other file of ght lines that indicates which should be printed, implying there are other blocks that should not be printed. If you have such a file and it looks like this:

    $ cat targets
    ght: ertyjk
    ght: YUIOPO
    

    and your other input file contains some ght: lines that do not match the above, e.g. see the ght: whatever blocks in the modified input file below:

    $ cat file
    xxx: rtyuiol
    ght: ertyjk
    
    xxx: ertyuikl_fghjk
    ght: ertyjk
    
    xxx: qwertyujkl
    ght: ertyjk
    
    xxx: rtyuiol_123
    ght: ertyjk
    
    xxx: foo
    ght: whatever
    
    xxx: bar
    ght: whatever
    
    xxx: rtyuiol
    ght: YUIOPO
    
    xxx: rtyuiopfghj
    ght: YUIOPO
    
    xxx: dfghjkvbnm
    ght: YUIOPO
    
    xxx: qzdfghnbvfgh
    ght: YUIOPO
    
    xxx: qsxcvghuiokmnhgf
    ght: YUIOPO
    

    then the above code would be updated to:

    awk '
        BEGIN { FS="\n" }
        NR==FNR {
            tgts[$0]
            next
        }
        $2 != prev {
            if ( inTgts = ($2 in tgts) ) {
                print $2
            }
            prev = $2
        }
        inTgts { print $1 }
    ' targets RS='' file
    ght: ertyjk
    xxx: rtyuiol
    xxx: ertyuikl_fghjk
    xxx: qwertyujkl
    xxx: rtyuiol_123
    ght: YUIOPO
    xxx: rtyuiol
    xxx: rtyuiopfghj
    xxx: dfghjkvbnm
    xxx: qzdfghnbvfgh
    xxx: qsxcvghuiokmnhgf
    
    • 2

相关问题

  • 重新排列字母并比较两个单词

  • 在awk中的两行之间减去相同的列

  • 多行文件洗牌

  • 如何更改字符大小写(从小到大,反之亦然)?同时[重复]

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve