Bash 脚本:更新属性文件
Bash scripting: update a properties file
propertyOne=1
propertyTwo=a/b
propertyThree=three
如何将 属性 文件的内容更改为以下模式?
- 属性一个会在原值前加一个字符串
- 属性两个会在中间加一个字符串
属性三个会在最后加一个字符串
propertyOne=apple/1
propertyTwo=a/and/b
propertyThree=three/end
我尝试使用 sed -i -e
,但只有对每一行的更改进行硬编码才能成功;有什么改进代码的建议吗?
sed -i -e '/propertyTwo=/ s=.*/=one/2/two' path/to/file
awk
救援!
$ awk -F'[=/]' '/propertyOne/{="apple/"}
/propertyTwo/{="/and/"}
/propertyThree/{="/end"}
{print "=" }' file
propertyOne=apple/1
propertyTwo=a/and/b
propertyThree=three/end
定义两个字段分隔符以便能够引用组件。根据您的规则设置新的第二个字段并打印。
注意 显然,如果您的内容中包含 /
或 =
,则此方法将不起作用。您可以概括第一个和最后一个规则以添加或附加到等式的值部分,但没有办法绕过第二种情况。
此外,为了更好地控制规则,您可能希望针对每种情况将 /../
更改为 =="..."
。
这是另一种选择,
$ awk -F= -v OFS='=' '=="propertyOne"{="apple/"}
=="propertyTwo"{sub(/\//,"/and/")}
=="propertyThree"{$NF=$NF"/end"}1' file
使用边缘案例进行测试
$ awk -F= ... << EOF
> propertyOne=a==b
> propertyTwo=a==b/c==d
> propertyThree=x/y==z
> Not_propertyOne=no change
> EOF
产量
propertyOne=apple/a==b
propertyTwo=a==b/and/c==d
propertyThree=x/y==z/end
Not_propertyOne=no change
在这种情况下,纯 Bash 解决方案 提供了灵活性和稳健性(但请参阅下文以了解更快的 awk
解决方案)。
虽然 Bash 逐行读取文件的解决方案通常很慢,但这可能不会成为属性文件的问题,因为属性文件往往很小。
#!/usr/bin/env bash
while IFS='=' read -r prop val; do
case $prop in
propertyOne)
val="apple/$val"
;;
propertyTwo)
val="${val/\///and/}"
;;
propertyThree)
val="$val/end"
;;
esac
printf '%s\n' "$prop=$val"
done < file > file.tmp && mv file.tmp file
Bash 内置 read
方便地提供了其余的行逻辑:
通过仅在 IFS='-' read -r prop value
中指定 2 个变量,第二个变量 value
接收 第一个 =
之后的所有内容,无论它是什么,即使它包含额外的 =
个实例。
< file > file.tmp && mv file.tmp file
是(松散地)就地更新文件的常用习惯用法。从技术上讲,修改后的内容被写入临时文件。文件和那个温度。然后文件替换原来的文件。
注:
* 需要这种间接更新方式,因为 shell 不支持在同一命令中读取和输出到同一文件。
* 这种简单的方法可能会有问题,因为如果输入文件是一个符号链接,它被替换为一个普通文件,新文件的权限可能不同,...
awk
,如 所示,当然是更快的选择,但它有一个警告 - 这可能是也可能不是你的问题:
从概念上讲,属性文件并非严格基于字段,因为属性值可能包含内部值 =
个实例。
如果您按 =
将输入拆分为字段,那么通用值处理可能会出现问题,因为您不会有一个 单个 变量引用该值整体。
一个简单的例子:假设您有一个输入行 foo=bar=baz
,并且您想要将字符串 @
附加到现有值 bar=baz
,而无需提前知道现有值是否恰好嵌入了 =
个字符。
如果您盲目地使用 = "@"
进行附加,结果值将只是 bar@
- 换句话说:您 丢失了数据 .
解决这个问题需要更多的工作;这是一个改编自 karakfa 的 awk
解决方案,它在单个变量 val
:
中提供 whole 值
awk -F= '
# Capture the entire value (everything to the right of "=") in variable "val".
{ val= [=11=]; sub("^[^=]+=", "", val) }
== "propertyOne" { val = "apple/" val }
== "propertyTwo" { sub(/\//, "/and/", val) }
== "propertyThree" { val = val "/end" }
{ print "=" val }
' file > file.tmp && mv file.tmp file
注意:如果你使用GNUawk
并且版本号>=4.1,你可以使用-i inplace
代替> file.tmp && mv file.tmp file
就地更新输入文件(松散地说)。 -i inplace
除了比后一种方式更方便之外,还保留了原文件的权限,但基本的做法是一样的:文件被替换,承担替换的风险带有常规文件的符号链接。
sed
不是一个好的选择,因为很难以通用方式将替换限制在一行的一部分。
propertyOne=1
propertyTwo=a/b
propertyThree=three
如何将 属性 文件的内容更改为以下模式?
- 属性一个会在原值前加一个字符串
- 属性两个会在中间加一个字符串
属性三个会在最后加一个字符串
propertyOne=apple/1 propertyTwo=a/and/b propertyThree=three/end
我尝试使用 sed -i -e
,但只有对每一行的更改进行硬编码才能成功;有什么改进代码的建议吗?
sed -i -e '/propertyTwo=/ s=.*/=one/2/two' path/to/file
awk
救援!
$ awk -F'[=/]' '/propertyOne/{="apple/"}
/propertyTwo/{="/and/"}
/propertyThree/{="/end"}
{print "=" }' file
propertyOne=apple/1
propertyTwo=a/and/b
propertyThree=three/end
定义两个字段分隔符以便能够引用组件。根据您的规则设置新的第二个字段并打印。
注意 显然,如果您的内容中包含 /
或 =
,则此方法将不起作用。您可以概括第一个和最后一个规则以添加或附加到等式的值部分,但没有办法绕过第二种情况。
此外,为了更好地控制规则,您可能希望针对每种情况将 /../
更改为 =="..."
。
这是另一种选择,
$ awk -F= -v OFS='=' '=="propertyOne"{="apple/"}
=="propertyTwo"{sub(/\//,"/and/")}
=="propertyThree"{$NF=$NF"/end"}1' file
使用边缘案例进行测试
$ awk -F= ... << EOF
> propertyOne=a==b
> propertyTwo=a==b/c==d
> propertyThree=x/y==z
> Not_propertyOne=no change
> EOF
产量
propertyOne=apple/a==b
propertyTwo=a==b/and/c==d
propertyThree=x/y==z/end
Not_propertyOne=no change
在这种情况下,纯 Bash 解决方案 提供了灵活性和稳健性(但请参阅下文以了解更快的 awk
解决方案)。
虽然 Bash 逐行读取文件的解决方案通常很慢,但这可能不会成为属性文件的问题,因为属性文件往往很小。
#!/usr/bin/env bash
while IFS='=' read -r prop val; do
case $prop in
propertyOne)
val="apple/$val"
;;
propertyTwo)
val="${val/\///and/}"
;;
propertyThree)
val="$val/end"
;;
esac
printf '%s\n' "$prop=$val"
done < file > file.tmp && mv file.tmp file
Bash 内置 read
方便地提供了其余的行逻辑:
通过仅在 IFS='-' read -r prop value
中指定 2 个变量,第二个变量 value
接收 第一个 =
之后的所有内容,无论它是什么,即使它包含额外的 =
个实例。
< file > file.tmp && mv file.tmp file
是(松散地)就地更新文件的常用习惯用法。从技术上讲,修改后的内容被写入临时文件。文件和那个温度。然后文件替换原来的文件。
注:
* 需要这种间接更新方式,因为 shell 不支持在同一命令中读取和输出到同一文件。
* 这种简单的方法可能会有问题,因为如果输入文件是一个符号链接,它被替换为一个普通文件,新文件的权限可能不同,...
awk
,如
从概念上讲,属性文件并非严格基于字段,因为属性值可能包含内部值 =
个实例。
如果您按 =
将输入拆分为字段,那么通用值处理可能会出现问题,因为您不会有一个 单个 变量引用该值整体。
一个简单的例子:假设您有一个输入行 foo=bar=baz
,并且您想要将字符串 @
附加到现有值 bar=baz
,而无需提前知道现有值是否恰好嵌入了 =
个字符。
如果您盲目地使用 = "@"
进行附加,结果值将只是 bar@
- 换句话说:您 丢失了数据 .
解决这个问题需要更多的工作;这是一个改编自 karakfa 的 awk
解决方案,它在单个变量 val
:
awk -F= '
# Capture the entire value (everything to the right of "=") in variable "val".
{ val= [=11=]; sub("^[^=]+=", "", val) }
== "propertyOne" { val = "apple/" val }
== "propertyTwo" { sub(/\//, "/and/", val) }
== "propertyThree" { val = val "/end" }
{ print "=" val }
' file > file.tmp && mv file.tmp file
注意:如果你使用GNUawk
并且版本号>=4.1,你可以使用-i inplace
代替> file.tmp && mv file.tmp file
就地更新输入文件(松散地说)。 -i inplace
除了比后一种方式更方便之外,还保留了原文件的权限,但基本的做法是一样的:文件被替换,承担替换的风险带有常规文件的符号链接。
sed
不是一个好的选择,因为很难以通用方式将替换限制在一行的一部分。