在配置文件中将两行合并为一行

时间:2015-04-07 15:09:14

标签: perl shell awk sed ksh

我有几个带有配置文件的AIX系统,我们称之为 / etc / bar / config 。该文件可能有也可能没有为 foo 声明值的行。一个例子是:

foo = A_1,GROUP_1,USER_1,USER_2,USER_3

foo 行在所有系统上可能相同也可能不同。不同的系统可以具有不同的值并且可以具有不同数量的值。我的任务是添加"最低限度"所有系统上 config 文件中的值。最低限度的行看起来像这样。

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 ,< em> 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 这是基于shell的某种类型我可以添加到我的更改脚本的代码段。我对其他选项持开放态度,特别是如果解决方案更简单的话。

4 个答案:

答案 0 :(得分:0)

未经测试的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

答案 1 :(得分:0)

此Perl代码将按您的要求执行。它期望将文件的路径修改为命令行上的参数。

请注意,它会将整个输入文件读入数组@config,然后使用修改后的数据覆盖同一文件。

它的工作原理是根据%values行中已存在的项目和foo =中默认项目列表的组合构建哈希@defaults。组合按字母顺序排序,并以逗号

连接
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

答案 2 :(得分:0)

一些脏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

答案 3 :(得分:0)

由于您没有提供样本输入和预期输出,我无法对此进行测试,但这是正确的方法:

awk '
/foo = / { old = ","$3; 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