【问题标题】:find - grep taking too much timefind - grep 花费了太多时间
【发布时间】:2017-02-15 13:30:14
【问题描述】:

首先,我是 bash 脚本的新手,如果我犯了简单的错误,请原谅我。

这是我的问题。我需要下载我公司的网站。我使用wget 完成此操作没有任何问题,但是因为某些文件具有? 符号并且windows 不喜欢? 的文件名,我必须创建一个脚本来重命名文件并更新所有文件的源代码调用重命名文件。

为此,我使用以下代码:

find . -type f -name '*\?*' | while read -r file ; do
 SUBSTRING=$(echo $file | rev | cut -d/ -f1 | rev)
 NEWSTRING=$(echo $SUBSTRING | sed 's/?/-/g')
 mv "$file" "${file//\?/-}"
 grep -rl "$SUBSTRING" * | xargs sed -i '' "s/$SUBSTRING/$NEWSTRING/g"
done

这有两个问题。

  1. 这花费的时间太长了,我已经等了 5 个多小时了,而且还在继续。
  2. 看起来像是在源代码中进行附加,因为当我停止脚本并搜索更改时,URL 会重复 4 次(或更多)。

感谢大家的 cmets,我将尝试 2 个单独的步骤,并且,正如仅供参考,使用 wget 下载了 3291 个文件,仍然认为使用 bash 脚本比其他工具更受欢迎?

【问题讨论】:

  • 你确定它真的在运行,而不仅仅是在等待输入吗?
  • 请注意,'?'您的某些 URL 中的字符会引入查询字符串。这表明底层资源可能是动态的,并且可能在不同的时间返回不同的内容。
  • 您可以通过首先回显从 find 命令找到的文件然后添加其他操作来进行增量调试。
  • 对于每个文件,您执行一个grep -rl "$SUBSTRING" * | xargs sed -i '' "s/$SUBSTRING/$NEWSTRING/g",该grep -rl "$SUBSTRING" * | xargs sed -i '' "s/$SUBSTRING/$NEWSTRING/g" 处理您运行它的目录中的所有文件,这需要很长时间并且没有用。
  • rev 显然是一种非常浪费的方式来处理${line##*/}。如果您非常想浪费外部进程,也可以使用basename 命令,但如果这里的任务是优化脚本,使用本机 Bash 似乎是可行的方法。

标签: bash macos shell sed grep


【解决方案1】:

一个文件似乎很奇怪?在里面。网站 URL 有 ?表示参数的传递。来自网站的 wget 也不能​​保证您获得该网站,特别是如果发生服务器端执行,例如 php 文件。因此,我怀疑 wget 进行递归时,它会查找 url 的传递参数,从而为您创建它们。

要真正获得该网站,您应该可以直接访问文件。

如果我是你,我会重新开始而不使用 wget。

您可能还会遇到名称中带有空格的文件或目录的问题。

您已经一次处理一个文件,而不是 xargs 行,而是递归地搜索所有文件。只需对新文件本身执行 sed。

【讨论】:

  • 您好,感谢您的回答,但不能直接访问文件,是的,这是一个 jsp 中的网站,它具有服务器端代码执行功能,因此这就是使用参数创建文件的原因。仅在我已经拥有的文件上使用 sed 的问题是,我需要更新站点中所有引用我正在重命名的文件的文件,这就是为什么我再次从根目录开始递归 grep 的原因。
  • 尽管您提出了合理的建议,但它并没有解决实际提出的问题,这些问题与操纵机器上已经存在的文件集合的名称和内容有关(已下载以前)。
【解决方案2】:

好的,这是这个想法(未经测试):

  • 在第一个循环中,只需移动文件并组成一个全局 sed 替换文件
  • 完成后,只需扫描所有文件并一次将sed 与所有模式一起应用,从而节省了大量可能导致性能问题的读/写操作
  • 我会避免把当前脚本放在当前目录下,否则会被sed处理,所以我想所有要处理的文件都不在当前目录下,而是在data目录下

代码:

sedfile=/tmp/tmp.sed
data=data
rm -f $sedfile
# locate ourselves in the subdir to preserve the naming logic
cd $data

# rename the files and compose the big sedfile

find . -type f -name '*\?*' | while read -r file ; do
 SUBSTRING=$(echo $file | rev | cut -d/ -f1 | rev)
 NEWSTRING=$(echo $SUBSTRING | sed 's/?/-/g')
 mv "$file" "${file//\?/-}"
 echo "s/$SUBSTRING/$NEWSTRING/g" >> $sedfile
done

# now apply the big sedfile once on all the files:    
# if you need to go recursive:
find . -type f  | xargs sed -i -f $sedfile
# if you don't:
sed -i -f $sedfile *

【讨论】:

  • 我很高兴这样做。我无法完全测试它。太棒了!
【解决方案3】:

您可以使用find 命令或ls 命令列出文件,然后直接对它们进行操作,而不是使用grep

例如,你可以这样做:

ls -1 /path/to/files/* | xargs sed -i '' "s/$SUBSTRING/$NEWSTRING/g"

这是我根据另一个问题得到这个想法的地方,grep 花了太长时间:

Linux - How to find files changed in last 12 hours without find command

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-23
    • 2013-07-11
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多