使用awk和sed消除不必要的输出

问题描述 投票:1回答:5

从下面的命令中,我如何消除之前出现的所有行

 Owner     RepoName             CreatedDate

编辑命令:

find /opt/site/ -name '.log.txt' | xargs cat | awk '{$NF=""; print $0}' | sed '1i Owner RepoName CreatedDate' | column -t

输出为

find: Filesystem loop detected; `/nfs/.snapshot/nightly.4' has the same device number and inode as a directory which is 2 levels higher in the filesystem hierarchy.
find: Filesystem loop detected; `/nfs/.snapshot/nightly.5' has the same device number and inode as a directory which is 2 levels higher in the filesystem hierarchy.
find: Filesystem loop detected; `/nfs/.snapshot/nightly.6' has the same device number and inode as a directory which is 2 levels higher in the filesystem hierarchy.
Owner     RepoName             CreatedDate
val        abc                  Fri          Mar  16  17:01:07  PDT
p1         repo_pc              Wed          Mar  21  11:34:42  PDT
New        fm                   Mon          Mar  19  00:15:51  PD 

仅是必需的输出:

Owner     RepoName             CreatedDate
val        abc                  Fri          Mar  16  17:01:07  PDT
p1         repo_pc              Wed          Mar  21  11:34:42  PDT
New        fm                   Mon          Mar  19  00:15:51  PD 
linux sed awk command
5个回答
3
投票

这些查找错误将出现在stderr上,因此完全绕开您的链,您将要使用2>/dev/null重定向错误,尽管这样做可以防止您在find命令中看到任何其他错误。

find /opt/site/ -name '.log.txt' 2>/dev/null | xargs cat | awk '{$NF=""; print $0}' | xargs sed "/Filesystem/d" | sed '1i Owner RepoName CreatedDate' | column -t

通常使用类似这样的复杂命令,当遇到错误时应将其分解,以便找出问题出处。

让我们分解该命令以查看其作用:

[find /opt/site/ -name '.log.txt' 2>/dev/null-在/ opt / site /下找到名为.log.txt的所有文件

xargs cat-依次获取所有内容

[awk '{$NF=""; print $0}'-删除最后一列

[xargs sed "/Filesystem/d"-将每个条目视为文件,并从那些文件的内容中删除任何包含Filesystem的行。

sed '1i Owner RepoName CreatedDate'-在第一行插入所有者RepoName CreatedDate

column -t-将给定的数据转换为表

我建议建立命令,并在每个阶段检查输出是否正确。

关于您的命令,有些事情令人惊讶:

  1. 发现者寻找的文件完全是.log.txt,而不是扩展名。
  2. 第二个xargs调用-将.log.txt文件的内容转换为文件名。

0
投票

您可以通过在第一个管道之前将2> / dev / null附加到命令的find部分来消除find的错误输出。 [编辑:这是最好的方法,我已经投票赞成道格拉斯(Douglas),因为他先在这里;)]

但是如果您真的想用sed或awk(不知道为什么?),可以修改awk脚本以跳过以'find:'开头的行:

awk '/^find:/ {next;} {$NF=""; print $0}' 

0
投票

可悲的是,您似乎正在使用csh或tcsh,在其中很难将标准错误与标准输出分开重定向。否则,道格拉斯的答案将奏效。但是尝试一下:

(find /opt/site/ -name '.log.txt' | xargs cat | awk '{$NF=""; print $0}' | sed '1i Owner RepoName CreatedDate' | column -t > output) >&/dev/null

请注意大部分命令周围的括号。在这些括号中,是将标准输出发送到名为“输出”的文件而不是终端的重定向(将其命名为您想要的任何名称,或者如果您确实想在终端中看到它,则将output替换为/dev/tty) 。在这些括号之外,是将其余错误消息发送到/dev/null的重定向。

整件事是关于可怕的贝壳寿命的悲惨评论。


0
投票

下一个sed命令应执行此工作(将其与输入文件或管道一起使用:

sed -n '/^Owner/,$ p'

说明:

-n             # Disable auto-print.
/^Owner/       # From a line beginning with 'Owner'...
$              # ...until end of input...
p              # print

0
投票

这完全可以通过Awk脚本执行...

#!/usr/bin/awk -f

BEGIN {
  for (i = 1; i < ARGC; i++) {
    if (ARGV[i] ~ "^--from=") {
      _from = substr(ARGV[i], 8)
      delete ARGV[i]
    }
  }

  if (!_from) {
    print "No '--from' argument provided!" > "/dev/stderr"
  }
}


{

  if (_flag) {
    print $0
  } else if ($0 ~ _from) {
    _flag = 1
    print $0
  }

}

注意;上面的脚本是从from-till.awk改编(修剪)的,将在from-till.awk--from搜索表达式之间打印,因此,针对此特定用例,可能需要调整添加的命令行选项和变量名称。

...允许将文件用作输入...

--till

...或重定向,例如head-trimmer.awk --from="^Owner" file-path.txt 或管道...

EOF

...和应该将事物解析为类似...

head-trimmer.awk --from="^Owner" <<'EOF'
find: Filesystem loop detected; `/nfs/.snapshot/nightly.4' has the same device number and inode as a directory which is 2 levels higher in the filesystem hierarchy.
find: Filesystem loop detected; `/nfs/.snapshot/nightly.5' has the same device number and inode as a directory which is 2 levels higher in the filesystem hierarchy.
find: Filesystem loop detected; `/nfs/.snapshot/nightly.6' has the same device number and inode as a directory which is 2 levels higher in the filesystem hierarchy.
Owner     RepoName             CreatedDate
val        abc                  Fri          Mar  16  17:01:07  PDT
p1         repo_pc              Wed          Mar  21  11:34:42  PDT
New        fm                   Mon          Mar  19  00:15:51  PD
EOF

... Awk脚本可以更轻松地扩展和/或适应其他用例,正确使用它意味着可以消除对其他程序的不必要调用。

应该可以从管道中消除Owner RepoName CreatedDate val abc Fri Mar 16 17:01:07 PDT p1 repo_pc Wed Mar 21 11:34:42 PDT New fm Mon Mar 19 00:15:51 PD sed,并提供一些提示


columnBEGIN blocks,其中Awk在all输入的开头和结尾处运行,例如。文件列表,因此非常适合构建标题和列映射


在Awk中将ENDwhile一起使用可解析命令的输出...

getline

当试图编写一个Bash脚本时,它很方便,Bash脚本只是带有一些自定义解析的命令的包装。


例如,有很多方便的内置Awk函数(GAwk则更多)。 #!/usr/bin/awk -f BEGIN { for (i = 1; i < ARGC; i++) { if (ARGV[i] ~ "^--directory=") { _directory = substr(ARGV[i], 13) delete ARGV[i] } if (ARGV[i] ~ "^--name=") { _name = substr(ARGV[i], 8) delete ARGV[i] } # ... perhaps add other args to parse } # ... build/print header maybe } { cmd = "find " _directory " -name " _name " 2>/dev/null" while (( cmd | getline _line ) > 0) { print "_line ->", _line # ... do some fancy formatting, use a built-in, or another command # to build desired column output from find results } close(cmd) # ... } split,并且可以通过Awk脚本中的length关键字添加更多内容。


Arrays / Dictionary变量也可以在Awk中使用,例如...

function

但是(如果我没记错的话),应该避免使用像[[BEGIN { for (i = 1; i < ARGC; i++) { if (ARGV[i] ~ "^--from=") { _custom_args["from"] = substr(ARGV[i], 8) delete ARGV[i] } else if (ARGV[i] ~ "^--till=") { _custom_args["till"] = substr(ARGV[i], 8) delete ARGV[i] } } } { # ... } 这样的多维数组,因为在Awk中,这种情况实际上是_something[0,1]


使用Awk将列打印为格式正确的表有些棘手,但也可以通过_something["0,1"]格式设置选项...

printf

基本上是#!/usr/bin/awk -f BEGIN { printf("%-8s %-13s %s\n", "Owner", "RepoName", "CreatedDate") } 告诉Awk至少保留%-8s个字符,而不考虑8的字符串长度,"Owner"保留%-13s,并且13告诉Awk用分隔符填充更长的字符串在字符串的右边/结尾。


为了防止与-结合使用的长刺,可能会有用...

printf


如果您被卡住,请随时发表评论,我将尝试使用更多技巧再次进行讨论。
© www.soinside.com 2019 - 2024. All rights reserved.