Bash - 搜索和替换操作,报告已更改的文件和行 [英] Bash - Search and Replace operation with reporting the files and lines that got changed

查看:205
本文介绍了Bash - 搜索和替换操作,报告已更改的文件和行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个输入文件test.txt,如下所示:

I have a input file "test.txt" as below -

hostname=abc.com hostname=xyz.com
db-host=abc.com db-host=xyz.com

,space之前的值是在名为test的文件夹中递归地递归之后需要用新值替换的旧值。

In each line, the value before space is the old value which needs to be replaced by the new value after the space recursively in a folder named "test". I am able to do this using below shell script.

#!/bin/bash

IFS=$'\n' 
for f in `cat test.txt`
do
  OLD=$(echo $f| cut -d ' ' -f 1) 
  echo "Old = $OLD"
  NEW=$(echo $f| cut -d ' ' -f 2)
  echo "New = $NEW"
  find test -type f | xargs sed -i.bak "s/$OLD/$NEW/g"
done

sed在100s的文件中替换字符串。

"sed" replaces the strings on the fly in 100s of files.

是否有一个技巧或替代方式,我可以得到一个文件的变化报告文件的绝对路径确切的线条得到了改变?

Is there a trick or an alternative way by which i can get a report of the files changed like absolute path of the file & the exact lines that got changed ?

我知道sed或流编辑器不支持这个功能。我不想使用版本控制,因为这对于这个任务来说是一个矫枉过正的事情。

PS - I understand that sed or stream editors doesn't support this functionality out of the box. I don't want to use versioning as it will be an overkill for this task.

推荐答案

让我们从简单的脚本重写入手,让它在处理更广泛的替换值,但也更快:

Let's start with a simple rewrite of your script, to make it a little bit more robust at handling a wider range of replacement values, but also faster:

#!/bin/bash

# escape regexp and replacement strings for sed
escapeRegex() { sed 's/[^^]/[&]/g; s/\^/\\^/g' <<<"$1"; }
escapeSubst() { sed 's/[&/\]/\\&/g' <<<"$1"; }

while read -r old new; do
    find test -type f -exec sed "/$(escapeRegex "$old")/$(escapeSubst "$new")/g" -i '{}' \;
done <test.txt

所以,我们循环了一对空格分隔的字段( old new )从 test.txt 并对所有使用 find 找到的文件执行标准的 sed 替换。

So, we loop over pairs of whitespace-separated fields (old, new) in lines from test.txt and run a standard sed in-place replace on all files found with find.

非常类似于您的脚本,但我们正确阅读 test.txt (不分词,路径名/变量扩展等),我们尽可能使用Bash内建函数(不需要调用外部工具,如 cat cut xargs );我们转义 sed code> old / new 的code>元字符作为 sed 的正则表达式和替换表达式。

Pretty similar to your script, but we properly read lines from test.txt (no word splitting, pathname/variable expansion, etc.), we use Bash builtins whenever possible (no need to call external tools like cat, cut, xargs); and we escape sed metacharacters in old/new values for proper use as sed's regexp and replacement expressions.

现在我们添加从sed登录

Now let's add logging from sed:

#!/bin/bash

# escape regexp and replacement strings for sed
escapeRegex() { sed 's/[^^]/[&]/g; s/\^/\\^/g' <<<"$1"; }
escapeSubst() { sed 's/[&/\]/\\&/g' <<<"$1"; }

while read -r old new; do
    find test -type f -printf '\n[%p]\n' -exec sed "/$(escapeRegex "$old")/{
        h
        s//$(escapeSubst "$new")/g
        H
        x
        s/\n/ --> /
        w /dev/stdout
        x
    }" -i '{}' > >(tee -a change.log) \;
done <test.txt

sed 脚本将每个旧的改为新的,但是它也写入 - >新的行到 / dev / stdout (Bash特定的),我们依次追加到 change.log 文件。 find 中的 -printf 操作为每个处理过的文件输出一个带有文件名的header行。

The sed script above changes each old to new, but it also writes old --> new line to /dev/stdout (Bash-specific), which we in turn append to change.log file. The -printf action in find outputs a "header" line with file name, for each file processed.

有了这个,你的更改日志就会变成这样:

With this, your "change log" will look something like:

[file1]
hostname=abc.com --> hostname=xyz.com

[file2]

[file1]
db-host=abc.com --> db-host=xyz.com

[file2]
db-host=abc.com --> db-host=xyz.com

为了完整起见,快速浏览 sed 脚本。我们只在包含旧的值的行上行动。对于每一个这样的行,我们存储它以保存空间( h ),将其更改为 new ,追加新值到现在持有 old \\\
new
的保留空间(以换行符连接, H )。我们用模式空间( x )交换保持,所以我们可以运行 s 命令将其转换为旧 - >新。在用 w 写入 stdout 之后,我们将 new 从保存到模式空间,所以它被写入(到位)到处理的文件。

Just for completeness, a quick walk-through the sed script. We act only on lines containing the old value. For each such line, we store it to hold space (h), change it to new, append that new value to the hold space (joined with newline, H) which now holds old\nnew. We swap hold with pattern space (x), so we can run s command that converts it to old --> new. After writing that to the stdout with w, we move the new back from hold to pattern space, so it gets written (in-place) to the file processed.

这篇关于Bash - 搜索和替换操作,报告已更改的文件和行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆