【问题标题】:Bash script, find command, using wildcards or regexBash 脚本,查找命令,使用通配符或正则表达式
【发布时间】:2019-06-14 13:11:06
【问题描述】:

我正在编写一个遍历特定目录中所有文件的 bash 脚本,并且:

  1. 选择名称与指定模式匹配的文件
  2. 按数据和时间排序(日期和时间是文件名的一部分)
  3. 获取 X 个最旧的文件
  4. 对它们执行某些操作

用于匹配文件的模式被传递给脚本,如下所示:

someprefix_[cats|dogs]_[oranges|apples|tomatos]_[2|3]*.txt

我尝试按如下方式实现(假设模式中的字段 6 和 7 包含日期和时间):

FILES=`find . -name "$PATTERN” | sort -t_ -k6 | head -n $NUM_OF_FILES`

它不起作用。 使用-name-regex 尝试了各种选项...... 大多数在线示例都是针对不太复杂的模式。 由于可能需要处理数十万个文件,因此我正在寻找一种有效的解决方案。 出于可读性原因,我想避免使用 sed。

【问题讨论】:

  • echo someprefix_[cats|dogs]_[oranges|apples|tomatos]_[2|3]*.txt 是否生成您要排序的文件列表?
  • @TomFenech 它没有,但以下适用于 ls:ls someprefix_{cats,dogs}_{oranges,apples,tomatos}_[2-3]*.txt。但是它不适用于 find 并且 sort 在应用于 ls 的结果时会出错。
  • 这可能会有所帮助:" !=
  • 您认为[cats|dogs] 在正则表达式中的含义是什么?在 globbing 模式中怎么样?我认为这两者都不是你想要的意思。因此,请弄清楚如何用任何一种语言编写您想要的内容,然后如何使用用该语言编写的表达式调用 find。

标签: linux bash command-line find


【解决方案1】:

您的 find 正则表达式必须匹配 find 返回的整个路径。例如,如果您在 somedir/ 搜索您的文件,那么您的正则表达式必须匹配,例如

somedir/prefix_cats_apples_2.txt

使图片复杂化的是,您是否可以通过将-regextype 选项更改为find 来使用多种类型的正则表达式,例如emacs (default), posix-awk, posix-basic, posix-egrep, posix-extended。 (posix-basic 没有修改能力)

posix-egrep 可能是您在 grep, sed, find, etc.. 等工具之间最容易转换的工具,posix-egrep 正则表达式用于您在 somedir/ 中搜索文件的模式将是:

'somedir/prefix_(cats|dogs)_(apples|oranges|tomatos).*[23].*$'

使用您的文件名匹配测试(结尾编号范围为0-3,以显示排除以0, 1 结尾的文件)使用以下示例文件:

$ls -1 somedir/
prefix_cats_apples_0.txt
prefix_cats_apples_1.txt
prefix_cats_apples_2.txt
prefix_cats_apples_3.txt
prefix_cats_oranges_0.txt
prefix_cats_oranges_1.txt
prefix_cats_oranges_2.txt
prefix_cats_oranges_3.txt
prefix_cats_tomatos_0.txt
prefix_cats_tomatos_1.txt
prefix_cats_tomatos_2.txt
prefix_cats_tomatos_3.txt
prefix_dogs_apples_0.txt
prefix_dogs_apples_1.txt
prefix_dogs_apples_2.txt
prefix_dogs_apples_3.txt
prefix_dogs_oranges_0.txt
prefix_dogs_oranges_1.txt
prefix_dogs_oranges_2.txt
prefix_dogs_oranges_3.txt
prefix_dogs_tomatos_0.txt
prefix_dogs_tomatos_1.txt
prefix_dogs_tomatos_2.txt
prefix_dogs_tomatos_3.txt

现在只匹配满足您的条件的文件并传递一般的sort 将产生:

$ find somedir/ -regextype posix-egrep -regex 'somedir/prefix_(cats|dogs)_(apples|oranges|tomatos).*[23].*$' | sort
somedir/prefix_cats_apples_2.txt
somedir/prefix_cats_apples_3.txt
somedir/prefix_cats_oranges_2.txt
somedir/prefix_cats_oranges_3.txt
somedir/prefix_cats_tomatos_2.txt
somedir/prefix_cats_tomatos_3.txt
somedir/prefix_dogs_apples_2.txt
somedir/prefix_dogs_apples_3.txt
somedir/prefix_dogs_oranges_2.txt
somedir/prefix_dogs_oranges_3.txt
somedir/prefix_dogs_tomatos_2.txt
somedir/prefix_dogs_tomatos_3.txt

由于您没有提供时间/日期在文件名中的位置的示例,因此您可以按时间/日期进行排序。如果您还有其他问题,请告诉我。

【讨论】:

  • 像魅力一样工作。感谢您详细的回答,对我帮助很大。特别感谢您的友好态度:)
【解决方案2】:

假设

  • 您的排序/过滤逻辑正常
  • 您不需要递归搜索
  • 文件名中没有换行符

我会用这个:

printf '%s\n' someprefix_{cats,dogs}_{oranges,apples,tomatos}_[23]*.txt \
    | sort -t_ -k6 \
    | head -n $NUM_OF_FILES

这使用 shell 的内置 glob 扩展功能来生成文件列表。每个结果都打印在单独的行上。使用与您的问题相同的管道处理输出。

【讨论】:

  • 不幸的是,这个对我不起作用。它返回值的所有可能组合(cats_oranges_[23]、dogs_oranges_[23] 等)。非常感谢您尝试提供帮助。
  • 那是因为模式与文件不匹配 - 我猜你运行脚本时可能在错误的目录中。
【解决方案3】:

与 find 函数匹配的默认正则表达式类型是 Emacs 正则表达式,因此模式的符号会有所不同。

如果我正确理解了您的模式,以下是有效的匹配命令:

find . '.*_\(cats\|dogs\)_\(oranges\|apples\|tomatos\)_\(2\|3\).*\.txt'

您可以找到有关 emacs here 的正则表达式类型和语法的任何信息。

希望有所帮助

【讨论】:

  • 调用这个 Emacs 正则表达式具有很大的误导性。 Emacs 正则表达式有很多find 不支持的特性,而find 支持的方言被许多非Emacs 工具支持。但是没有任何明智的正则表达式方言或通配符系统使用方括号,就像 OP 试图使用它们一样。
  • @Romain 我试过了,很遗憾没能成功。它返回目录中的所有文件,甚至那些根本不匹配模式的文件(如 text12.txt)。感谢您尝试提供帮助。我将阅读一些有关 emacs 正则表达式的内容。
  • @tripleee 我同意我对方括号的使用似乎是错误的。我将不胜感激帮助理解如何正确编写它。
  • The Stack Overflow regex tag info page 涵盖了许多常见的初学者常见问题解答,并有一个包含学习资源的可靠部分。
  • 无论如何,find 不接受谓词之外的正则表达式参数。你可能会得到它与-regex 一起工作,但我很确定这是未经测试的,很可能包含其他错误。如果文件碰巧存在于当前目录中,并且/或者您没有任何不应该匹配的文件,它可能“有效”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-17
  • 1970-01-01
  • 2022-01-13
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多