我可以在for循环中获取当前正在读取的文件的名称吗?

时间:2019-02-05 23:50:59

标签: linux bash macos

我想编写一个脚本,该脚本将单词作为参数,并在当前目录和子目录的文件中搜索该单词。如果在任何文件中找到它,它都应回显一条消息,其中包含文件名和找到该单词的行。

到目前为止,这是我所拥有的,但是我找不到真正存储所读取文件的文件名或行号的方法。

word=$1

for var in $(grep -R "$word *")
do   
filename=$(find . -type f -name "*")  ------- //this doesnt work
linenmbr=$(grep -n "$ord" file)     -----------    //this doesnt work
echo found $word in $filename on line number $linenmbr
done

1 个答案:

答案 0 :(得分:0)

在bash中,每次循环时,您都希望避免在循环内调用实用程序(例如grepfind)。这是非常低效的,因为它将在每次迭代时为每个实用程序生成一个单独的子外壳。 (对于10次迭代-即20个额外的子shell,它会很快累加起来)。因此,在您的情况下,您调用grep来填充循环,然后生成一个单独的子shell并调用{{1} }再次进入循环,并为grep生成一个单独的子shell。

您应该想到一种方法,仅调用一次find(或将提供所需信息的实用程序),然后解析输出。

如果您确实想使用grep,那么在用于馈送grep循环的进程替换中调用grep -rn可能和你会得到的。然后,您可以使用bash内置的参数扩展隔离文件名和行号,这些文件名和行号大约与bash可以获得的效率相同,例如

while

选择一种更有效的方法

如果您可以使用其中一种流编辑工具来完成尝试的工作,例如#!/bin/bash [ -z "$1" ] && { ## validate at least 1 input given printf "error: insufficient input.\nusage: %s srch_term\n" "${0##*/}" exit 1 } while read -r line; do ## read each line of grep output fn="${line%%:*}" ## isolate filename no="${line#*:}" ## remove filename no="${no%%:*}" ## isolate number printf "found %s in %s on line number %d\n" "$1" "$fn" "$no" done < <(grep -rn "$1") ## grep in process substitution awk,您可能能够更快地隔离所需信息。例如,使用sed并设置awk,您可以执行以下操作:

globstar

尝试一下,如果您还有其他问题,请告诉我。

如果要比较并确保两者都产生相同的输出,则可以使用#!/bin/bash shopt -s globstar ## set globstar [ -z "$1" ] && { ## validate at least 1 input given printf "error: insufficient input.\nusage: %s srch_term\n" "${0##*/}" exit 1 } ## find all matching files and line numbers awk -v word="$1" '/'$1'/ { print "found",word,"in",FILENAME,"on line number",FNR; next }' **/* 2>/dev/null 进行确认,例如

diff

(如果未报告差异,则输出相同)