从下面的命令中,我如何消除之前出现的所有行
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
这些查找错误将出现在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
-将给定的数据转换为表
我建议建立命令,并在每个阶段检查输出是否正确。
关于您的命令,有些事情令人惊讶:
您可以通过在第一个管道之前将2> / dev / null附加到命令的find部分来消除find的错误输出。 [编辑:这是最好的方法,我已经投票赞成道格拉斯(Douglas),因为他先在这里;)]
但是如果您真的想用sed或awk(不知道为什么?),可以修改awk脚本以跳过以'find:'开头的行:
awk '/^find:/ {next;} {$NF=""; print $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
的重定向。
整件事是关于可怕的贝壳寿命的悲惨评论。
下一个sed
命令应执行此工作(将其与输入文件或管道一起使用:
sed -n '/^Owner/,$ p'
说明:
-n # Disable auto-print.
/^Owner/ # From a line beginning with 'Owner'...
$ # ...until end of input...
p # print
这完全可以通过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
,并提供一些提示
column
和BEGIN
blocks,其中Awk在all输入的开头和结尾处运行,例如。文件列表,因此非常适合构建标题和列映射
在Awk中将END
与while
一起使用可解析命令的输出...
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]
_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
如果您被卡住,请随时发表评论,我将尝试使用更多技巧再次进行讨论。