1

我正在开发一个 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 脚本,我可以将通配符路径或文件名传递给它,它会搜索该文件,一旦它找到它搜索特定术语的文件并在找到时替换它。

听起来很简单,应该是这样,但我正把头撞在桌子上,因为我已经很久没有搞砸 bash 了……aaggghh 帮助!

4

5 回答 5

2
find $path -name \*$filenamepattern\* -exec sed -i.bak 's/find/replace/g' {} ';'
  • sed -i 将在文件中查找和替换保存回文件
  • 如果您不想备份文件,请删除 .bak 部分
  • 利用 find 的 -exec 选项来避免稍微麻烦的 xargs
于 2012-09-07T06:27:53.660 回答
2

首先,将变量名以大写形式声明是一个糟糕、糟糕、非常糟糕的主意,特别是PATH因为您实际上会重新设置实际的PATH环境变量(只需echo $PATH在提示中执行 a ,您就会明白我的意思,这可能是您必须使用/usr/bin/clear而不是clear因为 env 变量PATH被修改的原因之一)。因此,始终建议使用小写变量,例如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,,做会带你到按字母顺序排列的目录,即。因此,在父 shell 中没有引号将始终指向哪个不是我们想要的!/apps/data$ 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举个简单的例子。

警告- 如果您失败或忘记noglob回退 ( set +o noglob),shell 会将字符视为*?普通字符一样,并且不会扩展它们,这可能会导致不良结果和混乱。

于 2012-09-07T05:35:46.843 回答
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
于 2012-09-06T23:03:57.563 回答
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 {} ';'
  • 在命令行上调用此脚本时很重要,您必须反斜杠转义您的 glob;
    • % ./thisscript . \*.csv oldword newword
  • bash -f 选项在正确的时间关闭 globbing - 当第一次调用 bash subshel​​l 时,意味着在解析参数之前;
  • 在所有匹配的文件上查找命令 execs
  • 将搜索替换模式传递给包含脚本中其他已定义变量的 sed 的最简单方法是首先将模式本身放在变量中
  • -i.bak 选项使用替换创建一个新文件,并备份原始文件
于 2012-09-07T19:34:23.737 回答
0
find `filepath` -name `filename`|xargs sed 's/find/replace/'

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

于 2012-09-07T06:14:47.593 回答