在配置文件中将两行合并为一行
Merge two lines into one within a configuration file
我有几个带有配置文件的 AIX 系统,我们称之为 /etc/bar/config。该文件可能有也可能没有一行声明 foo 的值。一个例子是:
foo = A_1,GROUP_1,USER_1,USER_2,USER_3
foo 行在所有系统上可能相同也可能不同。不同的系统可能有不同的值和不同数量的值。我的任务是在所有系统的 config 文件中添加 "bare minimum" 值。最低限度的行将如下所示。
foo = A_1,USER_1,SYS_1,SYS_2
如果该行不存在,我必须创建它。如果该行确实存在,我必须合并这两条线。使用我的示例,结果将是这样的。值的顺序无关紧要。
foo = A_1,GROUP_1,USER_1,USER_3,USER_2,SYS_1,SYS_2
显然我想要一个脚本来完成我的工作。我有标准 sh、ksh、awk、sed, grep, perl, cut, 等。由于这是 AIX,我没有访问权限这些实用程序的 GNU 版本。
最初,我有一个包含这些命令的脚本来替换整个 foo 行。
cp /etc/bar/config /etc/bar/config.$$
sed "s/foo = .*/foo = A_1,USER_1,SYS_1,SYS_2/" /etc/bar/config.$$ > /etc/bar/config
但这只是替换了行。它确实考虑了任何预先存在的配置,包括缺少的一行。我正在脚本中进行其他配置修改,例如向其他文件添加完全独特的行并重新启动进程,所以我 perfer 这是某种类型的 [=54=我可以将基于 ] 的代码片段添加到我的更改脚本中。我对其他选择持开放态度,尤其是如果解决方案更简单的话。
未测试bash,等等
config=/etc/bar/config
default=A_1,USER_1,SYS_1,SYS_2
pattern='^foo[[:blank:]]*=[[:blank:]]*' # shared with grep and sed
if current=$( grep "$pattern" "$config" | sed "s/$pattern//" )
then
new=$( echo "$current,$default" | tr ',' '\n' | sort | uniq | paste -sd, )
sed "s/$pattern.*/foo = $new/" "$config" > "$config.$$.tmp" &&
mv "$config.$$.tmp" "$config"
else
echo "foo = $default" >> "$config"
fi
普通的 perl 解决方案:
perl -i -lpe '
BEGIN {%foo = map {$_ => 1} qw/A_1 USER_1 SYS_1 SYS_2/}
if (s/^foo\s*=\s*//) {
$found=1;
$foo{$_}=1 for split /,/;
$_ = "foo = " . join(",", keys %foo);
}
END {print "foo = " . join(",", keys %foo) unless $found}
' /etc/bar/config
此 Perl 代码将按您的要求执行。它期望将文件的路径修改为命令行上的参数。
请注意,它将整个输入文件读入数组 @config
,然后用修改后的数据覆盖同一文件。
它的工作原理是根据 foo =
行中已经存在的项目和 @defaults
中的默认项目列表构建散列 %values
。该组合按字母顺序排序并以逗号连接
use strict;
use warnings;
my @defaults = qw/ A_1 USER_1 SYS_1 SYS_2 /;
my ($file) = @ARGV;
my @config = <>;
open my $out_fh, '>', $file or die $!;
select $out_fh;
for ( @config ) {
if ( my ($pfx, $vals) = /^(foo \s* = \s* ) (.+) /x ) {
my %values;
++$values{$_} for $vals =~ /[^,\s]+/g;
++$values{$_} for @defaults;
print $pfx, join(',', sort keys %values), "\n";
}
else {
print;
}
}
close $out_fh;
输出
foo = A_1,GROUP_1,SYS_1,SYS_2,USER_1,USER_2,USER_3
有些脏bash/sed:
#!/usr/bin/bash
input_file="some_filename"
v=$(grep -n '^foo *=' "$input_file")
lineno=$(cut -d: -f1 <<< "${v}0:")
base="A_1,USER_1,SYS_1,SYS_2,"
if [[ "$lineno" == 0 ]]; then
echo "foo = A_1,USER_1,SYS_1,SYS_2" >> "$input_file"
else
all=$(sed -n ${lineno}'s/^foo *= */'"$base"'/p' "$input_file" | \
tr ',' '\n' | sort | uniq | tr '\n' ',' | \
sed -e 's/^/foo = /' -e 's/, *$//' -e 's/ */ /g' <<< "$all")
sed -i "${lineno}"'s/.*/'"$all"'/' "$input_file"
fi
由于您没有提供样本输入和预期输出,我无法对此进行测试,但这是正确的方法:
awk '
/foo = / { old = ","; next }
{ print }
END {
split("A_1,USER_1,SYS_1,SYS_2"old,all,/,/)
for (i in all)
if (!seen[all[i]]++)
new = (new ? new "," : "") all[i]
print "foo =", new
}
' /etc/bar/config > tmp && mv tmp /etc/bar/config
我有几个带有配置文件的 AIX 系统,我们称之为 /etc/bar/config。该文件可能有也可能没有一行声明 foo 的值。一个例子是:
foo = A_1,GROUP_1,USER_1,USER_2,USER_3
foo 行在所有系统上可能相同也可能不同。不同的系统可能有不同的值和不同数量的值。我的任务是在所有系统的 config 文件中添加 "bare minimum" 值。最低限度的行将如下所示。
foo = A_1,USER_1,SYS_1,SYS_2
如果该行不存在,我必须创建它。如果该行确实存在,我必须合并这两条线。使用我的示例,结果将是这样的。值的顺序无关紧要。
foo = A_1,GROUP_1,USER_1,USER_3,USER_2,SYS_1,SYS_2
显然我想要一个脚本来完成我的工作。我有标准 sh、ksh、awk、sed, grep, perl, cut, 等。由于这是 AIX,我没有访问权限这些实用程序的 GNU 版本。
最初,我有一个包含这些命令的脚本来替换整个 foo 行。
cp /etc/bar/config /etc/bar/config.$$
sed "s/foo = .*/foo = A_1,USER_1,SYS_1,SYS_2/" /etc/bar/config.$$ > /etc/bar/config
但这只是替换了行。它确实考虑了任何预先存在的配置,包括缺少的一行。我正在脚本中进行其他配置修改,例如向其他文件添加完全独特的行并重新启动进程,所以我 perfer 这是某种类型的 [=54=我可以将基于 ] 的代码片段添加到我的更改脚本中。我对其他选择持开放态度,尤其是如果解决方案更简单的话。
未测试bash,等等
config=/etc/bar/config
default=A_1,USER_1,SYS_1,SYS_2
pattern='^foo[[:blank:]]*=[[:blank:]]*' # shared with grep and sed
if current=$( grep "$pattern" "$config" | sed "s/$pattern//" )
then
new=$( echo "$current,$default" | tr ',' '\n' | sort | uniq | paste -sd, )
sed "s/$pattern.*/foo = $new/" "$config" > "$config.$$.tmp" &&
mv "$config.$$.tmp" "$config"
else
echo "foo = $default" >> "$config"
fi
普通的 perl 解决方案:
perl -i -lpe '
BEGIN {%foo = map {$_ => 1} qw/A_1 USER_1 SYS_1 SYS_2/}
if (s/^foo\s*=\s*//) {
$found=1;
$foo{$_}=1 for split /,/;
$_ = "foo = " . join(",", keys %foo);
}
END {print "foo = " . join(",", keys %foo) unless $found}
' /etc/bar/config
此 Perl 代码将按您的要求执行。它期望将文件的路径修改为命令行上的参数。
请注意,它将整个输入文件读入数组 @config
,然后用修改后的数据覆盖同一文件。
它的工作原理是根据 foo =
行中已经存在的项目和 @defaults
中的默认项目列表构建散列 %values
。该组合按字母顺序排序并以逗号连接
use strict;
use warnings;
my @defaults = qw/ A_1 USER_1 SYS_1 SYS_2 /;
my ($file) = @ARGV;
my @config = <>;
open my $out_fh, '>', $file or die $!;
select $out_fh;
for ( @config ) {
if ( my ($pfx, $vals) = /^(foo \s* = \s* ) (.+) /x ) {
my %values;
++$values{$_} for $vals =~ /[^,\s]+/g;
++$values{$_} for @defaults;
print $pfx, join(',', sort keys %values), "\n";
}
else {
print;
}
}
close $out_fh;
输出
foo = A_1,GROUP_1,SYS_1,SYS_2,USER_1,USER_2,USER_3
有些脏bash/sed:
#!/usr/bin/bash
input_file="some_filename"
v=$(grep -n '^foo *=' "$input_file")
lineno=$(cut -d: -f1 <<< "${v}0:")
base="A_1,USER_1,SYS_1,SYS_2,"
if [[ "$lineno" == 0 ]]; then
echo "foo = A_1,USER_1,SYS_1,SYS_2" >> "$input_file"
else
all=$(sed -n ${lineno}'s/^foo *= */'"$base"'/p' "$input_file" | \
tr ',' '\n' | sort | uniq | tr '\n' ',' | \
sed -e 's/^/foo = /' -e 's/, *$//' -e 's/ */ /g' <<< "$all")
sed -i "${lineno}"'s/.*/'"$all"'/' "$input_file"
fi
由于您没有提供样本输入和预期输出,我无法对此进行测试,但这是正确的方法:
awk '
/foo = / { old = ","; next }
{ print }
END {
split("A_1,USER_1,SYS_1,SYS_2"old,all,/,/)
for (i in all)
if (!seen[all[i]]++)
new = (new ? new "," : "") all[i]
print "foo =", new
}
' /etc/bar/config > tmp && mv tmp /etc/bar/config