Bash-搜索和替换操作,报告更改的文件和行
我有一个输入文件“test.txt”,如下所示-Bash-搜索和替换操作,报告更改的文件和行,bash,shell,sed,find,Bash,Shell,Sed,Find,我有一个输入文件“test.txt”,如下所示- hostname=abc.com hostname=xyz.com db-host=abc.com db-host=xyz.com 在每一行中,空格前的值是旧值,需要在名为“test”的文件夹中递归地用空格后的新值替换旧值。我可以使用下面的shell脚本来实现这一点 #!/bin/bash IFS=$'\n' for f in `cat test.txt` do OLD=$(echo $f| cut -d ' ' -f 1) ec
hostname=abc.com hostname=xyz.com
db-host=abc.com db-host=xyz.com
在每一行中,空格前的值是旧值,需要在名为“test”的文件夹中递归地用空格后的新值替换旧值。我可以使用下面的shell脚本来实现这一点
#!/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”在100个文件中动态替换字符串
是否有一种技巧或替代方法可以让我获得文件更改报告,如文件的绝对路径&更改的确切行数
PS-我知道sed或流编辑器不支持这种开箱即用的功能。我不想使用版本控制,因为这将是一个过度的任务 来自
人力资源
:
这可用于在替换时创建备份文件。然后,您可以查找任何备份文件,这些文件指示哪些文件已更改,以及diff
原始文件。检查完差异后,只需删除备份文件
如果您将替换公式化为
sed
语句,而不是自定义格式,则可以进一步使用sed
shebang行或将文件传递到-f/--file
,以便在一次操作中完成所有替换。来自man-sed
:
这可用于在替换时创建备份文件。然后,您可以查找任何备份文件,这些文件指示哪些文件已更改,以及diff
原始文件。检查完差异后,只需删除备份文件
如果您将替换公式化为
sed
语句,而不是自定义格式,则可以进一步使用sed
shebang行或将文件传递到-f/--file
在一个操作中执行所有替换操作。您的脚本有几个问题,只需使用(使用GNU awk代替GNU sed进行就地编辑):
您的脚本有几个问题,只需将其全部替换为(使用GNU awk而不是GNU 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 -exec sed "/$(escapeRegex "$old")/$(escapeSubst "$new")/g" -i '{}' \;
done <test.txt
上面的sed
脚本将每个old
更改为new
,但它也将old-->new
行写入/dev/stdout
(特定于Bash),然后我们将其附加到change.log
文件中。find
中的-printf
操作输出一个“头”带有文件名的行,用于处理的每个文件
这样,您的“更改日志”将如下所示:
[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
),将其更改为新值
,将该新值附加到保持空间(与新行连接,h
)它现在保存old\nnew
。我们用模式空间(x
)交换保留,这样我们可以运行s
命令,将其转换为old-->new
。在用w
将其写入stdout
后,我们将new
从保留移回模式空间,这样它就可以被写入(原地)处理的文件。让我们从简单地重写脚本开始,使其在处理更大范围的替换值时更加健壮,但也更快:
#!/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
上面的sed
脚本将每个old
更改为new
,但它也将old-->new
行写入/dev/stdout
(特定于Bash),然后我们将其附加到change.log
文件中。find
中的-printf
操作输出一个“头”带有文件名的行,用于处理的每个文件
这样,您的“更改日志”将如下所示:
[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
),将其更改为新值
,将该新值附加到保持空间(与新行连接,h
)它现在保存old\nnew
。我们用模式空间(x
)交换保留,这样我们可以运行s
命令,将其转换为old-->new
。在用w
将其写入stdout
后,我们将new
从保留移回模式空间,这样它就可以被写入(原地)处理的文件。好主意,我想了,但是当一个文件中有多个更改时,管理变得复杂。“sed”创建了多个扩展名为1.bak.bak.bak的文件。好主意,我想了,但是当一个文件中有多个更改时,管理变得复杂。“sed”创建多个扩展名为“.bak”的文件,如1.bak.bak.bak。
#!/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
[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