【问题标题】:Multiple grep separator and display file information多个grep分隔符并显示文件信息
【发布时间】:2021-10-03 23:08:52
【问题描述】:

我想用多个分隔符grep文件中的多个信息,并显示文件信息,只用一个命令。

./WBL-FILE-S-1-execution79065.html
./WBL-FILE-S-1-execution79066.html
./WBL-FILE-S-1-execution79067.html

如果我这样做:

find . -type f -name « *WBL-FILE* » | xargs grep "Fichier lu"

我的结果如下:

./WBL-FILE-S-1-execution79065.html:<td title="Message">Fichier&nbsp;lu&nbsp;/opt/data/in/bl/000334_iwel1C010116730.blc.TRT</td>
./WBL-FILE-S-1-execution79065.html:<td title="Message">Fichier&nbsp;lu&nbsp;/opt/data/in/bl/000312_iwel1C010116727.blc.TRT</td>
./WBL-FILE-S-1-execution74707.html:<td title="Message">Fichier&nbsp;lu&nbsp;/opt/data/in/bl/000420_iwel1C010116284.blc.TRT</td>

目标是获取文件的日期、文件名、XXXXXX_iwel 编号和 CXXXXXXXXX 编号。

例子:

2021-07-13 13:47 WBL-FILE-S-1-execution79065.html 000334 010116730
2021-07-13 14:48 WBL-FILE-S-1-execution79065.html 000312 010116727
2021-07-14 14:49 WBL-FILE-S-1-execution74707.html 000420 010116284

我几乎成功提取了不同的部分,但之后,我无法获取原始文件的“ls”(日期)信息。

有没有办法只用一行命令组合来做到这一点?

谢谢

【问题讨论】:

  • “一个命令”的概念在 Bash 中没有什么价值,因为您可以通过管道传输几乎所有内容来实现您的目标。例如,在您的命令中涉及 2 个命令:findxargs(也可以说 grep 是另一个命令)
  • 谢谢我更新了问题;)
  • « *WBL-FILE* » 语法无效;你的意思是"*WBL-FILE*"

标签: bash unix awk grep find


【解决方案1】:

如果你想添加文件的日期,单独grep 不会再删减它了。此外,单独使用 grep 无法提取 XXXXXX_iwel 和 CXXXXXXXXX 并将这些数字打印在同一行

因此我会切换到perl

perl -nle 'use POSIX "strftime";
BEGIN { sub mtime { strftime "%Y-%m-%d %H:%M:%S", localtime((stat $ARGV)[9]) } }
/Fichier&nbsp;lu.*?(\d+)_iwel.*?C(\d+)/ && print join " ", mtime, $ARGV, $1, $2'

你所有的文件都在同一个目录下,你可以使用

perl ... *WBL-FILE*

对于递归文件搜索,请使用 find -exec 而不是 find | xargs。这不仅更高效,而且在某些文件名包含空格或特殊符号(如"'\)的情况下也更安全。

find -type f -name '*WBL-FILE*' -exec perl ... {} +

【讨论】:

  • 非常感谢,我认为有一种更简单的方法可以做到,但它在某种意义上是合乎逻辑的 :)
【解决方案2】:

对于每个文件,您可以使用一个awk 命令显示您需要的信息。

awk 'match($0, /Fichier&nbsp;lu.*[^0-9]([0-9]*)_iwel[^C]*C([0-9]*)/, array) { date_command="date +\"%Y-%m-%d %H:%M:%S\" --date @$(stat -c %Y " FILENAME ")"; date_command | getline formatted_date; close(date_command); print formatted_date, FILENAME, array[1], array[2]}' /path/to/file

为了清楚起见,可以这样重写:

awk 'match($0, /Fichier&nbsp;lu.*[^0-9]([0-9]*)_iwel[^C]*C([0-9]*)/, array) {
  date_command="date +\"%Y-%m-%d %H:%M:%S\" --date @$(stat -c %Y " FILENAME ")";
  date_command | getline formatted_date;
  close(date_command);
  print formatted_date, FILENAME, array[1], array[2]
}'

基本上它做了三件事:

  • 它匹配包括Fichier&amp;nbsp;lu在内的所有行,并将XXXXXX_iwelCXXXXXXXXX的数字捕获到一个数组中
  • 调用命令行获取所需格式文件的修改日期
  • 它将您想要的所有信息打印在同一行上

当然可以在find之后插入。

find . -name "*WBL-FILE*" | xargs awk 'match($0, /Fichier&nbsp;lu.*[^0-9]([0-9]*)_iwel[^C]*C([0-9]*)/, array) { date_command="date +\"%Y-%m-%d %H:%M:%S\" --date @$(stat -c %Y " FILENAME ")"; date_command | getline formatted_date; close(date_command); print formatted_date, FILENAME, array[1], array[2]}'

结果:

2021-07-28 10:45:50 ./WBL-FILE-S-1-execution79065.html 000334 010116730
2021-07-28 10:45:50 ./WBL-FILE-S-1-execution79065.html 000312 010116727
2021-07-28 10:46:41 ./WBL-FILE-S-1-execution74707.html 000420 010116284

旁注

我使用了match 函数,它是GNU Awk 的一部分,也称为gawk。如果你没有它,它仍然是可能的,但它需要另一种方式来捕获字符串。

最棘手的部分可能是获取日期的命令,因为我们需要为命令构建一个字符串,然后调用它,然后将结果存储在一个变量中。有点乱。它还需要一个两步过程:获取 Epoch 时间中的日期(即从 1970-01-01 开始的秒数),然后使用 YYYY-MM-DD HH:MM:SS 格式格式化该值。另一方面,您可以非常轻松地调整这些步骤。例如,您可以通过将发送到date+\"%Y-%m-%d %H:%M:%S\" 字符串更改为另一种格式来显示日期。或者您可以通过更改发送到stat-c %Y 选项来显示创建日期而不是最后修改日期。

该命令对包含空格的文件名和文件夹不可靠。要解决此问题,首先您可以在日期调用期间使用难看的语法将$(stat -c %Y " FILENAME ")" 替换为$(stat -c %Y '"'"'" FILENAME "'"'"')"。哎呀。这是由于我们如何在一行中构建字符串。其次,您可以使用这些命令中的任何一个来确保正确传递文件名(为简化起见,假设 awk 脚本存储在 AWKSTRING 变量中)。

find . -name "*WBL-FILE*" -print0 | xargs -0 awk "$AWKSTRING"
find . -name "*WBL-FILE*" -exec awk "$AWKSTRING" {} \;
find . -name "*WBL-FILE*" -exec awk "$AWKSTRING" {} +

后者可能比其他的更好一点,但并非所有版本的find 都支持它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-11
    • 1970-01-01
    相关资源
    最近更新 更多