4

这是我的配置文件(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 列表。

4

6 回答 6

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下,每行由空格分隔为字段,每个字段由$iwhere iis the i th字段处理,每行的第一个字段是$1,每行的第二个字段$2最多到$NFwhereNF是包含字段数的变量在给定的行上。

所以脚本很简单:

  • 根据我们所需的字符串检查第一个字段$1=="banned-phrase"

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

于 2013-05-22T21:57:24.413 回答
4

你可以做

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

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

于 2013-05-22T21:57:14.777 回答
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

举个例子。一个更聪明的实现会首先读取列表文件,确保事情没有被禁止,等等。

于 2013-05-22T21:57:20.413 回答
1

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

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不会每次都刷新缓冲区。

于 2013-05-22T23:21:48.023 回答
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
于 2013-05-22T21:57:07.573 回答
0

最好使用 awk:

awk '$1 ~ /^banned-phrase/{print $2 >> "bannedphraselist"}
     $1 ~ /^banned-site/{print $2 >> "bannedsitelist"}' dansguardian-config
于 2013-05-22T22:01:11.380 回答