这是我的配置文件(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名单。
答案 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 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
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