你能向我解释一下下面的语句的作用吗?
grep `date +%Y-%m-%d --date='1 day ago'` /path/to/file/FILE_PREFIX_\`date +%Y%m%d --date='1 day ago'`.dsv | grep -v 'ERROR' | cut -d "|" -f 2 | sed 's/^0/27/'
答案1
假设我们有这个文件:
$ cat path/to/file/FILE_PREFIX_20150730.dsv
2015-07-29|0100
2015-07-30|0200
2015-07-30|0300
2015-07-31|0400
现在观察你的命令(稍微固定)的作用:
$ grep `date +%Y-%m-%d --date='1 day ago'` path/to/file/FILE_PREFIX_`date +%Y%m%d --date='1 day ago'`.dsv | grep -v 'ERROR' | cut -d "|" -f 2 | sed 's/^0/27/'
27200
27300
简而言之,它查看一个文件,其名称基于昨天的日期,path/to/file/FILE_PREFIX_20150730.dsv
.它在该文件中查找以 形式提及昨天日期的任何行2015-07-30
。然后它会消除任何也包含字符的行ERROR
。其余行根据字符分为多个字段|
。提取该行的第二个字段。如果第二个字段以零开头,则零将替换为27
。
答案2
首先,你给出的并不是一个声明。这是一堆通过链接在一起的命令管道和命令替换。
grep `date +%Y-%m-%d --date='1 day ago'` /path/to/file/FILE_PREFIX_\`date +%Y%m%d --date='1 day ago'`.dsv | grep -v 'ERROR' | cut -d "|" -f 2 | sed 's/^0/27/'
让我们把它们一一拆开。
命令替换
date +%Y-%m-%d --date='1 day ago'
出现两次并以格式给出昨天的日期YYYY-mm-dd
(例如 2015-07-31)- 第二次调用(路径名中的调用)将格式调整为
YYYYmmdd
- 将其放入反引号中使其成为命令替换。这与您通过
$(date +%Y-%m-%d --date='1 day ago')
仅键入后一种(和更新的)形式允许嵌套并且在转义方面不那么麻烦来实现的效果相同。
- 第二次调用(路径名中的调用)将格式调整为
的效果命令替换在你的命令行中类似于分配
YESTERDAY1=$(date +%Y-%m-%d --date='1 day ago')
YESTERDAY2=$(date +%Y%m%d --date='1 day ago')
然后像这样重写命令行
grep $YESTERDAY1 /path/to/file/FILE_PREFIX_$YESTERDAY2.dsv | grep -v 'ERROR' | cut -d "|" -f 2 | sed 's/^0/27/'
由管道链接的各个部件
grep $YESTERDAY1 /path/to/file/FILE_PREFIX_$YESTERDAY2.dsv
grep 查找文件中昨天日期的值/path/to/file/FILE_PREFIX_$YESTERDAY2.dsv
并将其输出到stdout
(请参阅标准流)grep -v 'ERROR'
grep 一切其他比包含ERROR
.它对来自的输入执行此操作stdin
,并且还写入stdout
。cut -d "|" -f 2
假设输入行(来自stdin
)由管道字符分隔(-d "|"
请注意管道字符在此处的字符串中的形式!),并选择第二个字段 (-f 2
) 并将其写入stdout
。sed 's/^0/27/'
将 ( ) 中(记住,原始输入的第二个字段)s/.../.../
中以 0 开头的所有字符串替换为 27,并将它们写入.stdin
^
stdout
管道
现在,出现在字符串之外的管道字符,即除了单个字符之外的所有字符都将前一个命令的cut -d "|" -f 2
链接到后一个命令。stdout
stdin
这样,第一个grep
读取文件的输出将转到第二个读取文件grep
的输出
这遵循Unix哲学原则“做一件事,并把它做好”。
把它们放在一起
在我的解释中,我使用了该变量YESTERDAY1
并YESTERDAY2
在命令替换部分中进行了介绍。现在你应该能够理解了。
不过有一件事。我怀疑会出现这种情况,但在午夜左右非常缓慢的系统上,运行这两个命令替换之间的时间可能足够长,足以产生不同的文件名值和我们grep
想要的值。
顺便一提
如果您想真正复杂并回避昨天的值可能会有所不同的问题,您可以使用参数扩展( ${parameter/pattern/string}
) 就这样。首先通过以下方式将日期放入变量中命令替换:
YESTERDAY=$(date +%Y-%m-%d --date='1 day ago')
然后使用参数扩展从变量的一个实例中删除破折号,如下所示:
grep $YESTERDAY /path/to/file/FILE_PREFIX_${YESTERDAY//-}.dsv | grep -v 'ERROR' | cut -d "|" -f 2 | sed 's/^0/27/'
这样,您只需检索日期值一次,并避免获得不同日期的(尽管很小)机会。
建议阅读
man
您系统上的Bash页面或这里- 这Bash 黑客维基
- 高级 Bash 脚本指南