使用 grep xargs sed 更有效地在文件中生成 UUID

Posted

技术标签:

【中文标题】使用 grep xargs sed 更有效地在文件中生成 UUID【英文标题】:Use grep xargs sed to regenerate UUIDs in a file more effeciently 【发布时间】:2021-12-24 22:11:43 【问题描述】:

我成功地能够用文件中新生成的 UUID 替换 UUID:

FILE=/home/username/sql_inserts_with_uuid.sql
grep -i -o -E "([a-f0-9]8-[a-f0-9]4-4[a-f0-9]3-[89aAbB][a-f0-9]3-[a-f0-9]12)" $FILE | xargs -I  sed -i "s//`uuidgen -t`/g" $FILE

但它很慢,因为它会为它生成的每个 UUID 重写文件。有没有更有效的方法来一次重写每个 UUID,而不是一遍又一遍地重写同一个文件?

将此示例数据保存在文件中进行测试:

INSERT INTO fake_table (uuid) VALUES ('812ab76e-43ca-11ec-b54f-00d8617c2296');
INSERT INTO fake_table (uuid) VALUES ('854f7b36-43ca-11ec-9608-00d8617c2296');
INSERT INTO fake_table (uuid) VALUES ('8a09444a-43ca-11ec-8ae2-00d8617c2296');
INSERT INTO fake_table (uuid) VALUES ('8cd0da58-43ca-11ec-9811-00d8617c2296');
INSERT INTO fake_table (uuid) VALUES ('8f9889c0-43ca-11ec-8bfc-00d8617c2296');

【问题讨论】:

此正则表达式 "([a-f0-9]8-[a-f0-9]4-4[a-f0-9]3-[89aAbB][a-f0-9]3-[a-f0-9]12)" 与您的示例不匹配。 生成一批uuid,放入文件中,将'uuid'文件和旧文件传递给awk进行替换;您需要将输出捕获到临时文件,并在完成后用临时文件覆盖旧文件;或者将一系列sed 脚本转储到脚本文件中,然后传递给sed -f;不确定使用并行操作更新同一目标文件的好处(竞争条件?混合输出?);似乎并发读/写(同一个文件)会比使用单个进程慢;所述单个进程应针对文件的单个读/写 【参考方案1】:

您可以将awk 与系统调用一起使用以一次性替换它们:

awk '
BEGINpat="[a-fA-F0-9]8-[a-fA-F0-9]4-[0-9][a-fA-F0-9]3-[89aAbB][a-fA-F0-9]3-[a-fA-F0-9]12"
function get_uuid()
    cmd = "uuidgen"
    cmd | getline uuid
    close(cmd)
    return uuid


$0~pat     
    uuid=get_uuid()
    sub(pat,uuid,$0)
 1
' file.txt

打印:

INSERT INTO fake_table (uuid) VALUES ('473C4331-CC31-4FD0-AE99-37FA7E5F23CF');
INSERT INTO fake_table (uuid) VALUES ('EBEC05AB-4236-4384-AF7A-76D4A0615599');
INSERT INTO fake_table (uuid) VALUES ('23740143-6CC1-41FC-8AE7-038810291026');
INSERT INTO fake_table (uuid) VALUES ('7DBF25AF-4E85-4C55-B8CA-0F6150D5DD3C');
INSERT INTO fake_table (uuid) VALUES ('4365127B-EB46-414E-92D4-B48CC211489E');

使用 GNU awk,您可以替换 inplace。否则,您需要将其输出重定向到一个临时文件,然后 mv 源文件顶部的临时文件。这听起来比actually is 更难。


速度测试:将您的示例文件乘以 10,000 个 UUID 替换,在我的计算机上处​​理该文件需要 21 秒,如果相同文件没有替换,则需要 26 毫秒。系统调用在效率方面不是免费的,但这可能比你正在做的更快......

【讨论】:

使用 GNU awk,您可以就地进行替换 根据您的链接:“inplace 扩展模拟 GNU sed 的 -i 选项,它执行“就地”编辑每个输入文件的...”如果它像 GNU sed 的“就地”选项,它实际上并不是就地的。它只是创建一个临时文件并重命名它。因此,您不能依赖未更改的 inode 或保持正确的硬链接。【参考方案2】:

在普通的 bash 中:

cat new_uuids

#!/bin/bash

hex='[[:xdigit:]]'
hex3="$hex$hex$hex"
hex4="$hex3$hex"
hex8="$hex4$hex4"
hex12="$hex8$hex4"
pat="$hex8-$hex4-[0-9]$hex3-[89aAbB]$hex3-$hex12"

while IFS= read -r line; do
    if [[ $line = *$pat* ]]; then
        echo "$line/$pat/$(uuidgen -t)"
    else
        echo "$line"
    fi
done

称之为

./new_uuids < sql_inserts_with_uuid.sql > new_sql_inserts_with_uuid.sql

【讨论】:

我在写类似的东西(但不知道[[:xdigit:]])。您不需要在while 循环中进行测试,只需echo 替换就足够了。从 2012 年开始,我的计算机上的速度约为 9 秒。 @Fravadona 正确,但在这种情况下,即使没有替换,uuidgen 也会被调用。这可能是可取的,也可能不是可取的,具体取决于匹配/不匹配行的比率。

以上是关于使用 grep xargs sed 更有效地在文件中生成 UUID的主要内容,如果未能解决你的问题,请参考以下文章

Linux命令之grep/sed/awk等行转列

shell grep 基本使用

linux下查找文件及文件内查找内容--find/grep/sed/awk

Linux grep、egrep使用命令详解

find grep xargs

sed后向引用取行及awk取列