在嵌套 files/directories 中使用正则表达式在一行中搜索多个字符串并输出匹配结果
Search multiple strings in one line using regex in nested files/directories and output matched results
例如有文件和目录:
/tmp/temp_dir/subdir_001/file_001.txt
/tmp/temp_dir/subdir_001/file_002.txt
/tmp/temp_dir/subdir_002/file_003.txt
/tmp/temp_dir/subdir_003/file_004.txt
并且这些内容包含可以通过正则表达式找到的特定行的各种内容。例如,这里是文件 file_001.txt
的内容:
abc cba
little boy writes -54321_12345 and goes to street 987
bca acb
little boy writes -12345_54321 and jumps to street 789
cab bac
我感兴趣的是那些以 little boy writes
开头的行。
我正在使用此正则表达式模式来查找我想保存为输出的重要数据:
little boy writes (\-\d+\_\d+).*street (\d+)
如何递归搜索并只输出匹配的字符串?所以在输出文件中我只会有这个:
54321_12345 987
12345_54321 789
find
和 sed
的组合应该可以解决问题:
find /tmp/temp_dir/ -type f -exec sed -En 's/little boy writes -([0-9]+_[0-9]+).*street ([0-9]+)/ /p' {} + > output
细分:
find /tmp/temp_dir/ -type f
: 我们从根文件夹递归地找到每个文件
-exec sed '... ' {} +
运行s 对找到的每个文件执行命令(这里 {}
表示 find
命令检索到的项目, +
表示命令再次执行一次最终结果,as explained here)
sed -En 's/little boy writes -([0-9]+_[0-9]+).*street ([0-9]+)/ /p'
:我们 运行 您在问题中描述的模式,使用 sed
(\d
不是有效的 sed 字符 class,我们使用 [0-9]
代替)
> output
我们将此命令的输出重定向到名为 output
的文件
您可以将 grep
与 sed
结合使用:
$ grep '^little boy writes' /tmp/temp_dir/subdir_*/file_*.txt | sed -re 's/^.* -([0-9]+_[0-9]+).*street ([0-9]+)/ /' > output.txt
你 可以 只用递归 grep
得到行,有或没有文件名。
grep -r '^little boy writes' * # lists source filenames
grep -hr '^little boy writes' * # does not
不过,这会报告整行。 Perl 模式匹配 (-P
) 与 -o
可能会检测到正确的行,并且只能检测到 return 你想要的位,但是对于大多数人来说,这种模式很难理解和维护,所以它是可能值得第二个过程-
grep -hr '^little boy writes' /tmp/temp_dir/subdir_[0-9][0-9][0-9]/file_[0-9][0-9][0-9].txt |
sed -E 's/[^0-9_]*([0-9_]+)/ /g'
或者如果你真的想在最后避免 space,
grep -hr '^little boy writes' /tmp/temp_dir/subdir_[0-9][0-9][0-9]/file_[0-9][0-9][0-9].txt |
's/^[^0-9_]*([0-9_]+)[^0-9_]*([0-9_]+$)/ /'
但是,如果您确切知道这些文件的位置足以进行这样的 globbing,那么您所需要的只是 sed。
sed -En '/^little boy writes/{ s/^[^0-9_]*([0-9_]+)[^0-9_]*([0-9_]+$)/ /g; p; }' /tmp/temp_dir/subdir_[0-9][0-9][0-9]/file_[0-9][0-9][0-9].txt
如果你不这样做,grep
and/or sed
可能会处理大量你可以避免的数据......也许你的目录结构不完全是这样持续的。在这种情况下,shopt
会有所帮助。
shopt -s globstar # let's ** stand for variable depth of subdirectories
sed -En '/^little boy writes/{ s/^[^0-9_]*([0-9_]+)[^0-9_]*([0-9_]+$)/ /g; p; }' **/file_[0-9][0-9][0-9].txt
这应该更有效(也更快)。它会让 OS 挑选匹配的文件并只将那些文件交给 sed
进行扫描。
这也只使用 sed
的一个实例,而不是使用 find
或需要 xargs
.
为每个文件生成一个实例
祝你好运。
例如有文件和目录:
/tmp/temp_dir/subdir_001/file_001.txt
/tmp/temp_dir/subdir_001/file_002.txt
/tmp/temp_dir/subdir_002/file_003.txt
/tmp/temp_dir/subdir_003/file_004.txt
并且这些内容包含可以通过正则表达式找到的特定行的各种内容。例如,这里是文件 file_001.txt
的内容:
abc cba
little boy writes -54321_12345 and goes to street 987
bca acb
little boy writes -12345_54321 and jumps to street 789
cab bac
我感兴趣的是那些以 little boy writes
开头的行。
我正在使用此正则表达式模式来查找我想保存为输出的重要数据:
little boy writes (\-\d+\_\d+).*street (\d+)
如何递归搜索并只输出匹配的字符串?所以在输出文件中我只会有这个:
54321_12345 987
12345_54321 789
find
和 sed
的组合应该可以解决问题:
find /tmp/temp_dir/ -type f -exec sed -En 's/little boy writes -([0-9]+_[0-9]+).*street ([0-9]+)/ /p' {} + > output
细分:
find /tmp/temp_dir/ -type f
: 我们从根文件夹递归地找到每个文件-exec sed '... ' {} +
运行s 对找到的每个文件执行命令(这里{}
表示find
命令检索到的项目,+
表示命令再次执行一次最终结果,as explained here)sed -En 's/little boy writes -([0-9]+_[0-9]+).*street ([0-9]+)/ /p'
:我们 运行 您在问题中描述的模式,使用sed
(\d
不是有效的 sed 字符 class,我们使用[0-9]
代替)> output
我们将此命令的输出重定向到名为output
的文件
您可以将 grep
与 sed
结合使用:
$ grep '^little boy writes' /tmp/temp_dir/subdir_*/file_*.txt | sed -re 's/^.* -([0-9]+_[0-9]+).*street ([0-9]+)/ /' > output.txt
你 可以 只用递归 grep
得到行,有或没有文件名。
grep -r '^little boy writes' * # lists source filenames
grep -hr '^little boy writes' * # does not
不过,这会报告整行。 Perl 模式匹配 (-P
) 与 -o
可能会检测到正确的行,并且只能检测到 return 你想要的位,但是对于大多数人来说,这种模式很难理解和维护,所以它是可能值得第二个过程-
grep -hr '^little boy writes' /tmp/temp_dir/subdir_[0-9][0-9][0-9]/file_[0-9][0-9][0-9].txt |
sed -E 's/[^0-9_]*([0-9_]+)/ /g'
或者如果你真的想在最后避免 space,
grep -hr '^little boy writes' /tmp/temp_dir/subdir_[0-9][0-9][0-9]/file_[0-9][0-9][0-9].txt |
's/^[^0-9_]*([0-9_]+)[^0-9_]*([0-9_]+$)/ /'
但是,如果您确切知道这些文件的位置足以进行这样的 globbing,那么您所需要的只是 sed。
sed -En '/^little boy writes/{ s/^[^0-9_]*([0-9_]+)[^0-9_]*([0-9_]+$)/ /g; p; }' /tmp/temp_dir/subdir_[0-9][0-9][0-9]/file_[0-9][0-9][0-9].txt
如果你不这样做,grep
and/or sed
可能会处理大量你可以避免的数据......也许你的目录结构不完全是这样持续的。在这种情况下,shopt
会有所帮助。
shopt -s globstar # let's ** stand for variable depth of subdirectories
sed -En '/^little boy writes/{ s/^[^0-9_]*([0-9_]+)[^0-9_]*([0-9_]+$)/ /g; p; }' **/file_[0-9][0-9][0-9].txt
这应该更有效(也更快)。它会让 OS 挑选匹配的文件并只将那些文件交给 sed
进行扫描。
这也只使用 sed
的一个实例,而不是使用 find
或需要 xargs
.
祝你好运。