在bash中解析配置文件

在bash中解析配置文件,bash,sed,awk,grep,Bash,Sed,Awk,Grep,这是我的配置文件(dansguardian配置): 我想写一个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" # a

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

我想写一个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
读取行时
做
#如果行以“禁止短语”开头
#将行的其余部分添加到文件bannedphraselist
#fi
#如果行以“禁止站点”开头
#将行的其余部分添加到文件bannedsitelist
#fi
完成
我不确定是否需要使用grep、sed、awk或其他什么

希望这是有道理的。我真的很讨厌DansGuardian列表。

在读取名称值时
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
做 如果[$name=禁用短语] 然后 echo$value>>横幅短语列表 elif[$name=被禁止的站点] 然后 echo$value>>横幅站点列表 fi 完成
你可以这样做

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

尽管这意味着要读取文件两次。不过,我怀疑可能的性能损失是否重要。

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

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
读取命令目标时;做
中的大小写“$command”
禁用短语)呼应“$target”>>横幅短语列表;;
被禁网站)回声“$target”>>横幅网站列表;;
"") ;; # 空行
*)echo>&2“$0:无法识别的配置指令'$command'”;;
以撒
完成
举个例子。更智能的实现将首先读取列表文件,确保事情没有被禁止,等等。

使用
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
$cat配置
禁语鸭蛙鸟
禁语马
被禁网站allaboutbirds.org duckduckgoose.net
被禁网站froggingbirds.gov
$awk'$1==“禁止短语”{for(i=2;i“bannedphraselist”}
$1==“被禁止的站点”{for(i=2;i“bannedsitelist”}'配置
$cat横幅短语列表
鸭子
青蛙
鸟
马
$cat横幅网站列表
allaboutbirds.org
duckgoose.net
青蛙鸟网站
说明:

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

所以脚本很简单:

  • 根据所需字符串检查第一个字段
    $1==“禁止短语”

  • 如果第一个字段匹配,则循环所有其他字段
    (i=2;i“bannedphraselist”

    • 更好地使用awk:

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

      使用
      echo text>>文件
      的所有解决方案都有什么问题?可以使用
      strace
      检查,在每一个这样的步骤中,打开
      文件
      ,然后定位到末尾,然后写入
      文本
      并关闭文件。因此,如果有1000次
      echo text>>文件
      ,那么将有10次00
      open
      lseek
      write
      close
      。可以通过以下方式大大减少
      open
      lseek
      close
      的数量:

      while read key val; do
        case $key in
        banned-phrase) echo $val>&2;;
        banned-site) echo $val;;
        esac
      done >bannedsitelist 2>bannedphraselist <dansguardian-config
      
      读取键val时执行
      
      案例$key in
      禁用短语)echo$val>&2;;
      禁止网站)echo$val;;
      以撒
      
      done>bannedsitelist 2>bannedphraselist+1。在纯Bash中可以做到这一点,但在清洁度和安全性之间有一个明显的折衷。使用Sed,您可以安全、干净地完成。不需要正则表达式匹配,也不需要附加,并且每行仅适用于一个值。@sudo_O:这个答案基于问题:
      如果行以“禁止短语”开头
      此外,我没有看到任何要求每行包含超过1个短语的要求……这并不意味着您必须使用正则表达式。当然,这可以通过在第一个字段上进行字符串比较来完成。@sudo\O:如果
      $1
      禁止的-phrase123
      ,那么您的解决方案将错误地解析该行并附加第二行内容我喜欢它的可读性(与awk、sed等相比)。如果配置文件中有这样的行:
      禁用短语鸭雉绿头鸭
      ?并且您可以在生成的文件中单独打印这些行吗?很好的解决方案。小注释:
      echo text>>文件
      每次调用时都将
      打开
      关闭
      。n使用
      exec 3>>文件
      echo text>&3
      可以大大减少此类调用的数量。这正是我所需要的,但语法太混乱了!我想我需要复习一下。我添加了一个简短的解释,希望能有所帮助。您可能想阅读一下这篇文章,了解awk的完整介绍非常好的解释!谢谢。+1!它只打开两个文件句柄一次,这是一个巨大的优势。它可以变得更短更神秘:
      awk'/^banked-(短语| site)/{gsub(/-/,“”,$1);for(i=2;i$1“list”}
      while read key val; do
        case $key in
        banned-phrase) echo $val>&2;;
        banned-site) echo $val;;
        esac
      done >bannedsitelist 2>bannedphraselist <dansguardian-config