使用 Bash 读取文件中的行并避免使用 # 行
Posted
技术标签:
【中文标题】使用 Bash 读取文件中的行并避免使用 # 行【英文标题】:Reading lines in a file and avoiding lines with # with Bash 【发布时间】:2012-01-02 00:22:33 【问题描述】:我试过了:
file="myfile"
while read -r line
do
[[ $line = \#* ]] && continue
"address=\$line\127.0.0.1"
done < "$file"
此代码不会避免以 cmets 开头的行。即使我没有任何 cmets,dnsmasq
也会告诉我有错误。
它将是一个dnsmasq
conf 文件,它将像这样读取和插入域名:address=\mydomain.com\127.0.0.1
。
编辑:1
输入文件:
domain1.com
domain2.com
domain3.com
#domain4.com
domain5.com
输出应该是:
address=/domain1.com/127.0.0.1
address=/domain2.com/127.0.0.1
address=/domain3.com/127.0.0.1
address=/domain5.com/127.0.0.1
我会将脚本放到 /etc/dnsmasq.d/ 目录中,以便dnsmaq.conf 可以在dnsmasq
启动时处理它。
【问题讨论】:
【参考方案1】:跳过以#
开头的行:
grep -v '^#' myfile | while read -r file ; do
...
done
根据需要修改grep
命令,例如,跳过以空格和#
字符开头的行。
【讨论】:
我不是反对者,但也许他们更喜欢显式子shell而不是隐式子shell?如:while IFS= read -r TI; do echo "$TI"; done < <(grep -v '#' ./items)
这个比原来的答案快。因为读取整个文件并执行 grep 比较慢。【参考方案2】:
使用[[ "$line" = "\#*" ]]
更安全
顺便说一句,address="\\$line\\127.0.0.1"
UPD:
如果我的理解正确,您需要将每个未注释的域更改为 address=\domain\127.0.0.1
。使用sed
可以快速轻松地完成,在 bash-program 中不需要。
$> cat ./text
domain1.com
domain2.com
domain3.com
#domain4.com
domain5.com
$> sed -r -e 's/(^[^#]*$)/address=\/\1\/127.0.0.1/g' ./text2
address=/domain1.com/127.0.0.1
address=/domain2.com/127.0.0.1
address=/domain3.com/127.0.0.1
#domain4.com
address=/domain5.com/127.0.0.1
如果您需要删除注释行,sed 也可以使用 /matched_line/d
完成此操作
$> sed -r -e 's/(^[^#]*$)/address=\/\1\/127.0.0.1/g; /^#.*$/d' ./text2
address=/domain1.com/127.0.0.1
address=/domain2.com/127.0.0.1
address=/domain3.com/127.0.0.1
address=/domain5.com/127.0.0.1
UPD2:如果你想在 bash 脚本中做所有这些事情,这里是你的代码修改:
file="./text2"
while read -r line; do
[[ "$line" =~ ^#.*$ ]] && continue
echo "address=/$line/127.0.0.1"
done < "$file"
它的输出:
address=/domain1.com/127.0.0.1
address=/domain2.com/127.0.0.1
address=/domain3.com/127.0.0.1
address=/domain5.com/127.0.0.1
【讨论】:
address=
不是变量。它是一个应该在所有行中重复的字符串。
你是什么意思repeated
?你想用address=\$line\127.0.0.1
替换像#*这样的所有行吗?
如果您显示您拥有的文件并显示您想要的文件,那就太好了。
我无法通过在 dnsmasq.conf 中添加脚本链接来让 dnsmasq 解析脚本。但是我创建了 dnsmasq 的 init 文件来执行脚本,并将链接添加到在 dnsmasq.conf 中作为输出获得的文件。它奏效了。
评论匹配应该是[[ "$line" = "#"* ]]
。系统/版本之间可能存在一些差异。【参考方案3】:
注释行可以而且经常以空格开头。这是一个处理任何前面空格的 bash 原生正则表达式解决方案;
while read line; do
[[ "$line" =~ ^[[:space:]]*# ]] && continue
...work with valid line...
done
【讨论】:
【参考方案4】:[ "$line:0:1" = "#" ] && continue
这需要字符串,在offset 0, length 1 处获取子字符串:
"$line:0:1"
并检查它是否等于#
= "#"
如果是则继续循环
&& continue
http://www.tldp.org/LDP/abs/html/string-manipulation.html
【讨论】:
谢谢你,我发现这很容易理解,解释得很好,而且不需要额外的复杂性(sed、awk 和以 ^ 开头的奇怪的令人毛骨悚然的语法)【参考方案5】:只有一个对我有用的是:
while IFS=$'\n' read line
do
if [[ "$line" =~ \#.* ]];then
logDebug "comment line:$line"
else
logDebug "normal line:$line"
fi
done < myFile
【讨论】:
【参考方案6】:您可以使用awk
进行过滤:
awk '!/^#/print"address=/"$0"/127.0.0.1"' file
【讨论】:
你能解释一下你的答案吗? 首先它说不打印以数字符号开头的行,然后在原始文本的两侧添加 $0,即要求的内容。【参考方案7】:这也可以通过 1 个sed
命令来完成:
file="myfile"
sed -i".backup" 's/^#.*$//' $file
这将就地修改文件(首先创建备份副本),删除所有以#
开头的行。
【讨论】:
【参考方案8】:它有 3 个部分。请阅读每个以清楚地理解
-
删除#行 -----
awk -F'#' 'print $1' t.txt
删除#创建的空行----awk 'NF > 0'
以所需格式打印。 ------awk 'print "address=/"$0"/127.0.0.1"'
所以需要的总脚本是,
**awk -F'#' 'print $1' t.txt | awk 'NF > 0' | awk 'print "address=/"$0"/127.0.0.1"'**
输出:
address=/domain1.com/127.0.0.1
address=/domain2.com/127.0.0.1
address=/domain3.com/127.0.0.1
address=/domain5.com/127.0.0.1
【讨论】:
【参考方案9】:awk ' if ($0 !~ /^#/)printf "address=/%s/127.0.0.1 \n",$0' <your_input_file>
【讨论】:
【参考方案10】:也许你可以试试
[[ "$line"~="#.*" ]] && continue
检查操作数中的~
!
【讨论】:
应该是 '=~' 而不是 '~='以上是关于使用 Bash 读取文件中的行并避免使用 # 行的主要内容,如果未能解决你的问题,请参考以下文章
如何删除错误行错误的行并使用 pandas 或 numpy 读取剩余的 csv 文件?