Shell 命令为属性键中被点包围的数字添加双引号

Déb*_*ora 6 shell awk sed

我有以下属性键

connection.party= 0.0.0.0
remote.app.328.port= 5432
remote.server.url="https://someurl.com?q=78.78"
remote.conncetion.7="basic"
remote.52.base= "local"
level1.34access23="true"
88.location.code=24
location.234.code.52=24 
Run Code Online (Sandbox Code Playgroud)

我需要将其转换为以下内容

connection.party= 0.0.0.0
remote.app."328".port= 5432
remote.server.url="https://someurl.com?q=78.78"
remote.conncetion."7"="basic"
remote."52".base= "local"
level1.34access23="true"
"88".location.code=24
location."234".code."52"=24
Run Code Online (Sandbox Code Playgroud)

嵌套属性键中具有前置或后置或两个点号的所有数字都需要使用双引号。不应更新与键中的文本连接的数字。(level1.34access23="true" => 无变化) 值无法更新。

我尝试使用以下内容,但它为所有内容添加了双引号。

sed -E 's/^([^=]+)\.([0-9]+)/\1."\2"/' input.properties 
Run Code Online (Sandbox Code Playgroud)

有人可以帮忙吗?

tri*_*eee 1

您的正则表达式显然也不需要在数字后加点,并且与表达式开头的数字不匹配。

\n

这是一个简单的脚本,它在两侧用点锚定数字,并且只要等号之前仍然有未引用的数字,就继续替换。

\n
sed -E -e 's/^([0-9]+)\\./"\\1"./' \\\n    -e :b -e 's/^([^=]+)\\.([0-9]+)\\./\\1."\\2"./' -e tb \\\n    -e 's/^([^=]+)\\.([0-9]+)=/\\1."\\2"=/' input.properties\n
Run Code Online (Sandbox Code Playgroud)\n

更详细地说,

\n\n

如果您在运行此脚本时遇到问题,请尝试将整个脚本放在单引号中:

\n
sed -E -e 's/^([0-9]+)\\./"\\1"./\n:b \n  s/^([^=]+)\\.([0-9]+)\\./\\1."\\2"./\n  tb\n  s/^([^=]+)\\.([0-9]+)=/\\1."\\2"=/' input.properties\n
Run Code Online (Sandbox Code Playgroud)\n

正如您所看到的,sed它几乎是一种只写语言。这是一个实现相同逻辑的简单 Awk 脚本。

\n
awk 'BEGIN { FS=OFS="=" }\n{ n = split($1, a, "."); f=""\n  for(i=1; i<=n; ++i)\n    f = (f ? f "." : "") (a[i] ~ /^[0-9]+$/ ? "\\"" a[i] "\\"" : a[i])\n  $1 = f}1' input.properties\n
Run Code Online (Sandbox Code Playgroud)\n

这也有些浓缩,但并不难理解(如果您认为它太晦涩,Awk 可以更轻松地手写内容)。

\n
    \n
  • 在开始处理任何输入之前,将输入字段分隔符FS和输出字段分隔符设置OFS为等号。

    \n
    BEGIN { FS=OFS="=" }\n
    Run Code Online (Sandbox Code Playgroud)\n

    这会导致$1包含第一个等号之前的所有内容,并且$2,$3等包含后续等号分隔字段。

    \n

    然后,对于每个输入行

    \n
  • \n
  • 将点上的第一个字段$1(即第一个等号之前的所有内容)拆分到数组中a。数组的长度为n。

    \n
    { n = split($1, a, ".");\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 创建一个空字符串变量,f我们将在其中累积 的替换值$1。

    \n
    f=""\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 循环 中的字段a,即从 1 到n:

    \n
    for(i=1; i<=n; ++i)\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 在循环中,f使用附加文本进行更新。

    \n
      \n
    • 如果f非空,则在 ; 的值后面添加一个点f。否则,只需保留一个空字符串,并与 ...\n 连接
      f = (f ? f "." : "")\n
      Run Code Online (Sandbox Code Playgroud)\n这使用三级运算符,如果为 true,则(expression ? value : othervalue)生成,否则生成。因此,换句话说,如果为非空,则产生 的当前值和文字点的串联;否则,产生一个空字符串。valueexpressionothervalueff"."
    • \n
    • ...与另一个三级表达式的结果连接,该表达式会产生a[i]带或不带双引号的结果,具体取决于它是否完全是数字。\n
      (a[i] ~ /^[0-9]+$/ ? "\\"" a[i] "\\"" : a[i])\n
      Run Code Online (Sandbox Code Playgroud)\n
    • \n
    \n
  • \n
  • 循环遍历值后,f将包含 的前一个值,$1但包含双引号引起来的任何全数字字段a。将其分配回$1.

    \n
    $1 = f\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 最后,打印修改后的行。

    \n
    }1\n
    Run Code Online (Sandbox Code Playgroud)\n

    右大括号终止我们对每个输入行执行的操作,而 \xc2\xb41` 只是一个简单的习惯用法,它使 Awk 打印每一行。

    \n

    (更详细地说,该值1作为条件应用,该条件始终为 true,没有任何操作,这意味着默认操作,即打印当前输入记录。)

    \n
  • \n
\n