在Linux和OSX上用唯一的guid替换每个匹配值的文本

在Linux和OSX上用唯一的guid替换每个匹配值的文本,linux,bash,macos,sed,Linux,Bash,Macos,Sed,我有一个文件夹,里面有一堆文件。在一些文件中有这样一行 id = "8c09e1ce-56b6-4aa5-8307-8998f507b594" 所有这些ids都是唯一的 我想编写一个命令,为所有ids生成新的唯一值 我有一个sed命令,该命令将匹配原始行's/id=\“[a-zA-Z0-9-]\{36\\\\\\”//g',但我不知道如何动态地使替换工作 有一些类似的StackOverflow问题(),但我无法获得跨OSX和Linux的可靠解决方案,这是我的要求之一。不过,它们都安装了uuid

我有一个文件夹,里面有一堆文件。在一些文件中有这样一行

id = "8c09e1ce-56b6-4aa5-8307-8998f507b594"
所有这些
id
s都是唯一的

我想编写一个命令,为所有
id
s生成新的唯一值

我有一个
sed
命令,该命令将匹配原始行
's/id=\“[a-zA-Z0-9-]\{36\\\\\\”//g'
,但我不知道如何动态地使替换工作

有一些类似的StackOverflow问题(),但我无法获得跨OSX和Linux的可靠解决方案,这是我的要求之一。不过,它们都安装了
uuidgen

显然,我更喜欢简洁易读的东西。

所以我(通过作弊)找到了答案

每个文件只有一个
id
,因此我决定对这些文件进行迭代,并分别为每个文件运行
sed
,如下所示:

for i in `find . -name "*.extension" -type f`; do
    uuid=$(uuidgen)
    sed -i '' -e "s/id = \"[a-zA-Z0-9-]\{36\}\"/id = \"${uuid}\"/g" $i
done

如果可以一次性完成,这个问题仍然是一个一般情况。

对于使用
sed
-i
选项进行编辑,没有跨平台语法可以在不创建备份文件的情况下工作,正如我的一篇文章中所解释的(您必须使用
-i'
(BSD/macOS)或只使用
-i
(GNU),但在创建备份文件时,类似于
-i.bak
的内容可用于这两种实现)

也就是说,
awk
无论如何都是此任务的更好工具,因为awk脚本允许根据需要调用shell命令和外部实用程序:

find . -type f -name '*.extension' | while IFS= read -r fpath; do
  awk '
    BEGIN { FS=OFS=" = " } 
    $2 ~ /^\"[a-zA-Z0-9-]+\"$/ { "uuidgen" | getline uuid; $2 = "\"" uuid "\"" }
    1
  ' "$fpath" > "$fpath.tmp" && mv "$fpath.tmp" "$fpath"
done
这假设文件名没有内嵌的换行符,这在现实世界中很少引起关注

  • 该命令仅使用与POSIX兼容的shell功能、实用程序和选项,以下情况除外:

    • uuidgen的
      uuidgen
      实用程序,但是,它在Linux和macOS以及FreeBSD及其变体上都可用
  • 不幸的是,Mawk(Ubuntu的默认Awk)不支持重复表达式,例如
    {36}
    ,这就是为什么上面使用了不太具体的
    +
    ;但是,如果您知道您将只使用BSD或GNU Awk,那么您仍然可以使用
    {36}

  • 该命令支持替换每个输入文件中的多个UUID


另一方面:GNU Awk v4.1+允许使用
-i inplace
进行就地更新,类似于Sed的
-i
选项,该选项允许使用
-exec
执行单个命令
查找
解决方案,但是BSD Awk和Mawk都不支持它。

您提到的ID字符串的预期输出是什么。hey@Inian我想用所有这些文件中的新guid替换guid值,请。另外,您的
sed-i'
仅适用于BSD sed,而不适用于GNU sed。请双引号
$i
,以确保其值按原样使用。Sed脚本的
s
函数调用中的
g
选项是不需要的,因为每个输入行最多有一个UUID。