Bash脚本搜索文件并使用通配符替换在文件中找到的字符串

时间:2012-09-06 22:54:37

标签: linux bash shell unix

我正在研究一个bash脚本,它会搜索一个特定的文件,使用通配符路径进行搜索,一旦找到该文件名,它会在文件中搜索特定的术语,然后替换它。

这就是我已经把它放在一起的东西:

#!/bin/sh

PATH=${1}
FILENAME="$2"
SEARCHFOR="$3"

/usr/bin/clear
echo "Searching $PATH"
echo "For the file $FILENAME"
echo "With the string $SEARCHFOR"
echo "=========================="
echo "       RESULTS            "
echo "=========================="
/usr/bin/find $PATH -type f -name "$FILENAME" | /usr/bin/xargs /bin/grep -l "$SEARCHFOR"

我还没有添加替换品,但我想我会使用SED代替grep来做这件事,只是使用grep进行测试。

使用上面的代码,我必须为任何类型的通配符路径使用引号。有办法解决这个问题吗?

./script '/home/*/public_html' php.ini module.so

我在考虑使用参数,但必须采用另一种方法。

我的最终目标是拥有一个bash脚本,我可以传递通配符路径或文件名,它会搜索该文件,一旦找到它搜索特定术语的文件,并在找到时替换它。

听起来很简单,应该是这样,但是我正撞在桌子上,因为我已经被打扰了很长时间......我帮忙了!

5 个答案:

答案 0 :(得分:2)

首先,以大写形式声明变量名称是一个坏的,坏的,非常糟糕的主意,尤其是PATH,因为你实际上是在重新设置实际的PATH环境变量(只是在提示符中执行echo $PATH,您就会理解我的意思,这可能是您必须使用/usr/bin/clear代替clear的原因之一,因为env变量{{1得到修改)。因此,始终建议使用小写的变量,如PATH


您遇到的问题是子shell中path扩展glob。当你使用

*

./script '/home/*/public_html' php.ini module.so 未在提示符处展开(父shell),但在脚本的子shell中展开。但是当你使用

*

./script /home/*/public_html php.ini module.so 在父shell中展开(这会导致shell指向一个随机路径),然后在程序子shell中传递 -

让我们说,*有目录/home/user/apps执行/data会将您带到按字母顺序排列的目录,即{{ 1}}。因此,父shell中没有引号的$ cd *将始终指向/apps,这不是我们想要的!

立即采取补救措施如下

/home/*

/home/apps

尝试$set -o noglob #unset glob expansion $./script /home/*/public_html php.ini module.so #your command without quotes & wildcard */ $set +o noglob #re-set glob expansion back 然后$set -o noglob;./script /home/*/public_html php.ini module.so;set +o noglob 以获得快速示例。

警告 - 如果您失败或忘记将$echo *设置回$set -o noglob;echo *;set +o noglob),则shell会处理noglobset +o noglob等字符像普通字符一样,不会扩展它们,这可能会导致不良结果和混乱。

答案 1 :(得分:2)

find $path -name \*$filenamepattern\* -exec sed -i.bak 's/find/replace/g' {} ';'
  • sed -i将在文件中找到并替换并保存回文件
  • 如果您不想备份文件,请删除.bak部分
  • 使用find-utilc选项来避免稍微繁琐的xargs

答案 2 :(得分:1)

只需重新排序您的参数,并在最后放置您要搜索的目录列表。所以:

#!/bin/sh

FILENAME="${1?No filename specified}"
SEARCHFOR="${2?No target string given}"
shift; shift;
SEARCHPATH="$@"

然后你应该能够保持其余的不变(除了将名称PATH更改为SEARCHPATH,因为更改PATH是一个非常糟糕的主意)并将其命名为:

$ ./script php.ini module.so /home/*/public_html

答案 3 :(得分:0)

find `filepath` -name `filename`|xargs sed 's/find/replace/'

对我来说,我会用find和sed来完成这项工作。

答案 4 :(得分:0)

这将解决将通配符传递给bash脚本的问题但请遵守第一个要点。

#!/bin/bash -f

directory=$1
filename=$2
searchfor=$3
replacement=$4

sedpattern=s/$searchfor/$replacement/g

find $directory -name $filename -exec sed -i.bak $sedpattern {} ';'
  • 重要事项在命令行上调用此脚本时,必须反斜杠 - 转义全局;
    • % ./thisscript . \*.csv oldword newword
  • bash -f选项在正确的时间关闭globbing - 首次调用bash subshel​​l时,意味着在解析参数之前;
  • 在匹配
  • 的所有文件上找到命令execs sed
  • 将搜索替换模式传递给包含脚本中其他已定义变量的sed的最简单方法是将模式本身放在变量中
  • -i.bak选项使用替换创建新文件,并备份原始文件