linux - 如何在 bash 中使用 'while ..; do..; done'

标签 linux bash shell awk command-line

<分区>

我在 bash 中使用此命令执行操作时遇到问题。以下是我所拥有的:

cat namelist | while read line; do awk '$1 == $line {print $0}' Jan.txt; done

namelist 是一个不重复的名单,每一行都有每个名字。而 Jan.txt 是这样的信息文件:

ermartin pts/10       Tue Jan 19 09:49 - 10:15  (00:26)     171.66.208.139
sdou     pts/6        Tue Jan 19 01:52 - 22:20 (9+20:27)    131.243.186.99
sdou     pts/2        Tue Jan 19 01:20 - 22:20 (9+20:59)    131.243.186.99
phu      pts/2        Sat Jan 16 12:21 - 15:13  (02:52)     lbl-ipsec-7667.dhcp.lbl.gov
phu      pts/2        Sat Jan 16 10:07 - 12:01  (01:54)     lbl-ipsec-7622.dhcp.lbl.gov
sjames   pts/5        Fri Jan 15 12:06 - 13:06  (01:00)     lakshmi.lbl.gov
ermartin pts/2        Fri Jan 15 08:36 - 12:43  (04:07)     171.66.208.134
ermartin pts/2        Fri Jan 15 08:31 - 08:36  (00:05)     171.66.208.134
camitche pts/4        Thu Jan 14 15:18 - 20:47  (05:28)     171.66.208.134
ermartin pts/2        Thu Jan 14 13:20 - 15:57  (02:36)     171.66.208.139
ermartin pts/2        Thu Jan 14 12:35 - 13:00  (00:25)     171.66.208.139
sjames   pts/2        Thu Jan 14 06:17 - 06:27  (00:09)     phys1.als.lbl.gov
sjames   pts/2        Thu Jan 14 06:17 - 06:17  (00:00)     phys1.als.lbl.gov
ermartin pts/0        Wed Jan 13 15:19 - 15:50  (00:31)     171.66.208.139
ermartin pts/0        Wed Jan 13 07:55 - 08:09  (00:13)     c-24-130-14-154.hsd1.ca.comcast.net

我只是试图将 namelist 中的名称与该文件匹配,然后对该文件中的每一行信息执行操作,但是当我执行 $1 == $line,它说这是一个错误。如何正确使用此命令?

是否也可以遍历月份并将它们打印为标题,如下所示:

[Jan] 
sjames ...hours 
sdou ...hours 

[Feb] 
sjames ...hours 
sdou ...hours

最佳答案

首先,awk 和 shell 不共享变量。但是,可以使用 -v 选项将 shell 变量传输到 awk 变量。以下工作正常,对代码的唯一更改是添加 -v line="$line" 选项:

cat namelist | while read line; do awk -v line="$line" '$1 == line {print $0}' Jan.txt; done

请注意,awk 将 line 变量引用为不带美元符号的 line

上述管道的可能替代品是:

awk 'FNR==NR{a[$1]; next;} $1 in a' namelist Jan.txt

在这里,关联数组 a 跟踪 namelist 中的名称,并使用它来决定是否打印 Jan.txt 中的行。

如果您不打算对数据进行更多处理(但我认为情况恰恰相反),那么,正如 Shellter 在评论中所建议的那样,上述内容可以替换为:

grep -Ff namelist Jan.txt

如果你想计算 namelist 中用户使用的时间,那么试试:

$ awk -F'[ +:()]+' 'FNR==NR{a[$1]; next;} !($1 in a){next} NF==13{b[$1]+=$12+60*$11} NF==14{b[$1]+=$13+60*($12+24*$11)} END{for (n in b)print n,b[n]}' namelist Jan.txt

例如,考虑这个名单:

$ cat namelist 
sdou
phu

计算的时间是:

$ awk -F'[ +:()]+' 'FNR==NR{a[$1]; next;} !($1 in a){next} NF==13{b[$1]+=$12+60*$11} NF==14{b[$1]+=$13+60*($12+24*$11)} END{for (n in b)print n,b[n]}' namelist Jan.txt
phu 286
sdou 28406

为了可读性,可能更容易看到相同的代码分布在多行中:

awk -F'[ +:()]+' '
  FNR==NR{
    a[$1]
    next
  }

  !($1 in a){
    next
  }

  NF==13{
    b[$1]+=$12+60*$11
  }

  NF==14{
    b[$1]+=$13+60*($12+24*$11)
  }

  END{
    for (n in b)
      print n,b[n]
  }
  ' namelist Jan.txt
phu 286

按用户和按月跟踪使用情况:

$ awk -F'[ +:()]+' 'FNR==NR{a[$1]; next;} !($1 in a){next} NF==13{b[$1"["$4"]"]+=$12+60*$11} NF==14{b[$1"["$4"]"]+=$13+60*($12+24*$11)} END{for (n in b)print n,b[n]}' namelist Jan.txt
phu[Jan] 286
sdou[Jan] 28406

关于linux - 如何在 bash 中使用 'while ..; do..; done',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38575256/

相关文章:

bash - shell : get function's body by it's name

linux - 如何使用脚本中的密码从 shell 脚本登录用户帐户?

shell - .bashrc、.bash_profile 和 .environment 之间有什么区别?

c++ - rand() 函数的动态链接器错误

linux - 使用 docker-machine 更改文件组

bash - 如何定义单词的参数?

bash - 将 shell 参数存储在文件中,同时保留引号

linux - shell 编程: Executing two applications at the same time

linux - TensorFlow 多 GPU InvalidArgumentError : cifar10_multi_gpu. py

linux - 为什么内核使用默认 block 驱动程序而不是我的驱动程序代码?