在bash中解析配置文件

时间:2013-05-22 21:51:22

标签: bash sed awk grep

这是我的配置文件(dansguardian-config):

banned-phrase duck

banned-site allaboutbirds.org

我想编写一个bash脚本,它将读取此配置文件并为我创建一些其他文件。这是我到目前为止所做的,它主要是伪代码:

while read line
do
    # if line starts with "banned-phrase"
        # add rest of line to file bannedphraselist
    # fi

    # if line starts with "banned-site"
        # add rest of line to file bannedsitelist
    # fi
done < dansguardian-config

我不确定我是否需要使用grep,sed,awk或者什么。

希望这是有道理的。我真的很讨厌DansGuardian名单。

6 个答案:

答案 0 :(得分:5)

使用awk

$ cat config
banned-phrase duck frog bird
banned-phrase horse
banned-site allaboutbirds.org duckduckgoose.net
banned-site froggingbirds.gov

$ awk '$1=="banned-phrase"{for(i=2;i<=NF;i++)print $i >"bannedphraselist"}
       $1=="banned-site"{for(i=2;i<=NF;i++)print $i >"bannedsitelist"}' config

$ cat bannedphraselist 
duck
frog
bird
horse

$ cat bannedsitelist 
allaboutbirds.org
duckduckgoose.net
froggingbirds.gov

<强>解释

默认情况下,awk每行按空格分隔为字段,每个字段由$i处理,其中i是i th 字段每行的第一个字段为$1,每行的第二个字段为$2,最高为$NF,其中NF是包含该数字的变量给定行上的字段。

所以脚本很简单:

  • 根据我们所需的字符串$1=="banned-phrase"

  • 检查第一个字段
  • 如果第一个字段匹配,则循环遍历所有其他字段for(i=2;i<=NF;i++)并打印每个字段print $i并将输出重定向到文件>"bannedphraselist"

答案 1 :(得分:4)

你可以做到

sed -n 's/^banned-phrase *//p' dansguardian-config > bannedphraselist
sed -n 's/^banned-site *//p' dansguardian-config > bannedsitelist

虽然这意味着两次读取文件。我怀疑可能的性能损失很重要。

答案 2 :(得分:4)

您可以一次读取多个变量;默认情况下,它们会在空格上分开。

while read command target; do
  case "$command" in
    banned-phrase) echo "$target" >>bannedphraselist;;
    banned-site) echo "$target" >>bannedsitelist;;
    "") ;; # blank line
    *) echo >&2 "$0: unrecognized config directive '$command'";;
  esac
done < dansguardian-config

仅作为一个例子。一个更聪明的实现将首先读取列表文件,确保事情尚未被禁止等等。

答案 3 :(得分:1)

使用echo text >> file的所有解决方案有什么问题?可以使用strace检查在每个此类步骤中file是否已打开,然后定位到结尾,然后写入text并关闭文件。因此,如果有{1000} echo text >> file次,则会有1000 openlseekwritecloseopenlseekclose的数量可以通过以下方式减少很多:

while read key val; do
  case $key in
  banned-phrase) echo $val>&2;;
  banned-site) echo $val;;
  esac
done >bannedsitelist 2>bannedphraselist <dansguardian-config

stdout和stderr被重定向到文件并在循环处于活动状态时保持打开状态。因此文件打开一次并关闭一次。不需要lseek。此外,文件缓存的使用方式也更多,因为对close的不必要调用每次都不会刷新缓冲区。

答案 4 :(得分:0)

while read name value
do
  if [ $name = banned-phrase ]
  then
    echo $value >> bannedphraselist
  elif [ $name = banned-site ]
  then
    echo $value >> bannedsitelist
  fi
done < dansguardian-config

答案 5 :(得分:0)

最好使用awk:

awk '$1 ~ /^banned-phrase/{print $2 >> "bannedphraselist"}
     $1 ~ /^banned-site/{print $2 >> "bannedsitelist"}' dansguardian-config