linux下快速查找包含指定内容的文件
linux下查找包含指定内容的文件经常需要用到两个指令,find与grep。
find命令
find的基本作用为在目录层次结构中搜索指定的文件,其基本语法如下:
find [-H] [-L] [-P] [-D debugopts] [-Olevel] [starting-point...] [expression]
下面介绍常用的find用法:
- Find files by extension:
find {{root_path}} -name '{{*.ext}}'
- Find files matching multiple path/name patterns:
find {{root_path}} -path '{{**/path/**/*.ext}}' -or -name '{{*pattern*}}'
- Find directories matching a given name, in case-insensitive mode:
find {{root_path}} -type d -iname '{{*lib*}}'
- Find files matching a given pattern, excluding specific paths:
find {{root_path}} -name '{{*.py}}' -not -path '{{*/site-packages/*}}'
- Find files matching a given size range:
find {{root_path}} -size {{+500k}} -size {{-10M}}
- Run a command for each file (use
{}
within the command to access the filename):
find {{root_path}} -name '{{*.ext}}' -exec {{wc -l {} }}\;
- Find files modified in the last 7 days and delete them:
find {{root_path}} -daystart -mtime -{{7}} -delete
- Find empty (0 byte) files and delete them:
find {{root_path}} -type {{f}} -empty -delete
grep命令
grep命令在指定的文件中搜索符合pattern的行,并输出
其基本语法如下:
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] -e PATTERN ... [FILE...]
grep [OPTIONS] -f FILE ... [FILE...]
grep的常用方法如下:
- Search for a pattern within a file:
grep "{{search_pattern}}" {{path/to/file}}
- Search for an exact string (disables regular expressions):
grep --fixed-strings "{{exact_string}}" {{path/to/file}}
- Search for a pattern in all files recursively in a directory, showing line numbers of matches, ignoring binary files:
grep --recursive --line-number --binary-files={{without-match}} "{{search_pattern}}" {{path/to/directory}}
- Use extended regular expressions (supports
?
,
+
,
{}
,
()
and
|
), in case-insensitive mode:
grep --extended-regexp --ignore-case "{{search_pattern}}" {{path/to/file}}
- Print 3 lines of context around, before, or after each match:
grep --{{context|before-context|after-context}}={{3}} "{{search_pattern}}" {{path/to/file}}
- Print file name and line number for each match:
grep --with-filename --line-number "{{search_pattern}}" {{path/to/file}}
- Search for lines matching a pattern, printing only the matched text:
grep --only-matching "{{search_pattern}}" {{path/to/file}}
- Search stdin for lines that do not match a pattern:
cat {{path/to/file}} | grep --invert-match "{{search_pattern}}"
find与grep的配合使用
当我们想要搜索当前目录下哪些文件包含所需要的内容时,我们可以将find与grep组合起来使用。
比如,当前目录结构如下:
想要在scripts中搜索哪些.sh中包含"make"字符,我写下以下指令进行尝试:
find . -name "*.sh" | grep "make"
但却惊讶的发现,输出为空,并没有任何输出,但这些sh文件中明明包含了“make”。
之所以出现这个问题的原因,是因为我错误理解了“|”——管道的作用,"|"会将前一个指令:
find . -name "*.sh"
的输出作为输入发送给grep指令,但是它发送的是一个整体,即将整个find的结果:
./build_armv7.sh
./build_armv8.sh
./build-linux.sh
./execute_linux_test.sh
./build_hisi3516.sh
发送给grep,grep只会从上述的结果文本中去寻找是否存在make,而不是自动解析出文件名,来一行一行的grep文件内容。
可以从以下命令语句中证明这个结论:
find . -name "*.sh" | grep "linux"
得到结果:
./build-linux.sh
./execute_linux_test.sh
正如上述所说,它是从文本中找到了包含"linux"的哪些行。
但是如何解决从每个".sh"中找到想要的信息呢,这时需要用到另一个指令xargs。
xargs
xargs一般用来获取来自上一个管道的参数,来作为下一个命令的输入,它将上一个管道的参数作为一个整体块,然后根据空格,tabs,新的一行等进行分割成多个参数,让下一个命令执行。
基本语法为:
xargs [options] [command [initial-arguments]]
xargs的常用用法如下:
- Run a command using the input data as arguments:
{{arguments_source}} | xargs {{command}}
- Run multiple chained commands on the input data:
{{arguments_source}} | xargs sh -c "{{command1}} && {{command2}} | {{command3}}"
- Delete all files with a
.backup
extension (
-print0
uses a null character to split file names, and
-0
uses it as delimiter):
find . -name {{'*.backup'}} -print0 | xargs -0 rm -v
- Execute the command once for each input line, replacing any occurrences of the placeholder (here marked as
_
) with the input line:
{{arguments_source}} | xargs -I _ {{command}} _ {{optional_extra_arguments}}
- Parallel runs of up to
max-procs
processes at a time; the default is 1. If
max-procs
is 0, xargs will run as many processes as possible at a time:
{{arguments_source}} | xargs -P {{max-procs}} {{command}}
真正的内容检索
根据以上所学知识,我们可以真正的来实现在.sh中搜索包含make的那些文件了,输入指令:
find . -name "*.sh" | xargs grep "make"
成功获得了想要的结果:
./build_armv7.sh:make -j8 || exit 1
./build_armv8.sh:make test_time -j8 || exit 1
./build-linux.sh:cmake .. \
./build-linux.sh: -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain/clang-x86_64-linux-gnu.toolchain.cmake \
./build-linux.sh:make detector_unit_test -j8 || exit 1
./build_hisi3516.sh:cmake .. \
./build_hisi3516.sh: -DCMAKE_TOOLCHAIN_FILE=../cmake/arm.himix200.toolchain.cmake \
./build_hisi3516.sh:make -j8 || exit 1