Bash 语句的作用是什么

Bash 语句的作用是什么

你能向我解释一下下面的语句的作用吗?

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.dsvgrep 查找文件中昨天日期的值/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链接到后一个命令。stdoutstdin

这样,第一个grep读取文件的输出将转到第二个读取文件grep的输出

这遵循Unix哲学原则“做一件事,并把它做好”

把它们放在一起

在我的解释中,我使用了该变量YESTERDAY1YESTERDAY2在命令替换部分中进行了介绍。现在你应该能够理解了。

不过有一件事。我怀疑会出现这种情况,但在午夜左右非常缓慢的系统上,运行这两个命令替换之间的时间可能足够长,足以产生不同的文件名值和我们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/'

这样,您只需检索日期值一次,并避免获得不同日期的(尽管很小)机会。

建议阅读

相关内容