我想编写一个脚本,该脚本将单词作为参数,并在当前目录和子目录的文件中搜索该单词。如果在任何文件中找到它,它都应回显一条消息,其中包含文件名和找到该单词的行。
到目前为止,这是我所拥有的,但是我找不到真正存储所读取文件的文件名或行号的方法。
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
答案 0 :(得分:0)
在bash中,每次循环时,您都希望避免在循环内调用实用程序(例如grep
和find
)。这是非常低效的,因为它将在每次迭代时为每个实用程序生成一个单独的子外壳。 (对于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
(如果未报告差异,则输出相同)