如何从两行文本中获取特定信息并据此组合文件名

如何从两行文本中获取特定信息并据此组合文件名

我目前正在编写一个脚本来存档几个日志文件,并希望将它们合并到一个存档中,该存档根据其中一个日志文件(即access.log)中第一行和最后一行的日期和时间命名。

但就我而言,我无法弄清楚如何从这些行中获取这些信息并将其组合成文件名。

有问题的行来自 apache.log 文件,我可以使用head和简单地获取它tail

例子:

$ head -n1 /home/server/log/access.log.1 
84.1.11.243 - - [21/Jan/2017:14:53:49 +0000] "GET /index.php/2016/05/26/tutorial-how-to-install-ubuntu-and-other-debian-based-distributions-via-debootstrap/ HTTP/1.1" 200 18413 "https://www.google.hu/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"

$ tail -n1 /home/server/log/access.log.1 
71.3.17.120 - - [20/Dec/2017:16:17:50 +0000] "POST / HTTP/1.1" 200 27639 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; LCTE; rv:11.0) like Gecko"

预期的文件名结果应该包括这些消息的日期和时间戳。

我想使用示例行,但可以根据答案结果进行更改:

tar -caf "backup-logfiles-$start-til-$end.tar.gz" access.log error.log ftp.log

欢迎使用任何解决方案将该值提取到$start和中$end

答案1

下面是一个非常复杂的 shell 单行代码(使用你在聊天中提到):

$ name=$(printf 'backup-logfiles-%s-til-%s' $(date -d "$(head -n1 logfile | grep -oP '\[\K\S+' | sed 's|/| |g; s/:/ /')" +%Y-%m-%d-%H:%M:%S) $(date -d "$(tail -n1 logfile | grep -oP '\[\K\S+' | sed 's|/| |g; s/:/ /')" +%Y-%m-%d-%H:%M:%S))
$ echo $name
logfiles-2017-01-21-14:53:49-til-2017-12-20-16:17:50

要分别获取开始和结束变量,请执行以下操作:

$ start=$(head -n1 logfile | grep -oP '\[\K\S+' | sed 's|/|-|g; s/:/ /')
$ end=$(tail -n1 logfile | grep -oP '\[\K\S+' | sed 's|/|-|g; s/:/ /')
$ echo "backup-logfiles-$start-til-$end.tar.gz"
backup-logfiles-21-Jan-2017 14:53:49-til-20-Dec-2017 16:17:50.tar.gz

或者,如果您想要一个数字日期:

$ start=$(date -d "$(head -n1 logfile | grep -oP '\[\K\S+' | sed 's|/|-|g; s/:/ /')" +%Y-%m-%d-%H:%M:%S)
$ end=$(date -d "$(tail -n1 logfile | grep -oP '\[\K\S+' | sed 's|/|-|g; s/:/ /')" +%Y-%m-%d-%H:%M:%S)
$ echo "backup-logfiles-$start-til-$end.tar.gz"
backup-logfiles-2017-01-21-14:53:49-til-2017-12-20-16:17:50.tar.gz

答案2

仅使用sed,仅用于乐趣赢得高尔夫比赛 ;)

name=$(sed -rn 's|/|-|g;s/.* \[([^ ]+) .*/\1/;1p;$p' file | sed 'N;s/\n/-til-/')
$ echo $name
21-Jan-2017:14:53:49-til-20-Dec-2017:16:17:50

但是如果您想将此文件传递给tar,冒号可能会导致问题:

An  archive  name  that has a colon in it specifies a file or device on a remote
machine.  The part before the colon is taken as the machine name or IP address,
and the part after it as the file or device pathname, e.g.:

    --file=remotehost:/dev/sr0

您可以通过传递一个选项来解决这个问题:

--force-local
      Archive file is local even if it has a colon.

但是这里有一个用更多连字符替换冒号的命令:

name=$(sed -rn 's|[/:]|-|g;s/.* \[([^ ]+) .*/\1/;1p;$p' file | sed 'N;s/\n/-til-/')

我们可以使用交替来代替字符类并节省一个字节:)

name=$(sed -rn 's#/|:#-#g;s/.* \[([^ ]+) .*/\1/;1p;$p' file | sed 'N;s/\n/-til-/')

笔记

  • -r使用 ERE
  • -n在我们要求之前不要打印任何内容
  • s|/|-|g用 替换所有/字符-(因为我们不能使用 文件名/
  • s|[/:]|-|g/用连字符替换:所有位置的字符。
  • s#/|:#-#g替换/:-所有地方
  • ;单独的sed命令
  • s/.* \[([^ ]+) .*/\1/捕获方括号内(从第一个[到第一个空格)的日期和时间。
  • 1p;$p仅打印第一行和最后一行
  • |将其通过管道输送到另一个sed(呃!)
  • N将两行读入模式空间......
  • s/\n/-til-/...所以我们可以用以下方法替换换行符-til-

相关内容