gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:14:44 24 4
gpt4 key购买 nike

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

这是我目前所拥有的,但我找不到一种方法来实际存储正在读取的文件的文件名或行号。

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

最佳答案

在 bash 中,无论何时循环,您都希望避免在循环中调用实用程序(例如 grepfind)。这是非常低效的,因为它会在每次迭代时为每个实用程序生成一个单独的子 shell。 (对于 10 次迭代 - 即 20 额外的子外壳,它加起来很快)所以在你的情况下,你调用 grep 来提供循环,然后产生一个单独的子 shell 在循环中再次调用 grep 并为 find 生成一个单独的子 shell。

您应该想办法只调用 grep(或提供所需信息的实用程序)一次,然后解析输出。

如果您确实想使用 grep,则在用于提供 进程替换中调用 grep -rn while 循环可能和您将要得到的一样好。然后,您可以使用 bash 内置的参数扩展 来隔离文件名和行号,这将与 bash 一样高效,例如

#!/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

选择更高效的方法

如果您可以使用其中一种流编辑工具(例如awksed,您可能能够更快地隔离所需信息一个数量级。例如,使用 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 来确认,例如

$ diff <(grepscript.sh | sort) <(awkscript.sh | sort)

(如果没有报错,输出是一样的)

关于linux - 我可以在 for 循环中获取当前正在读取的文件的名称吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54544799/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com