使用 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 &lt; &lt;(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 &gt; 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 文件?

抓取两个日期时间之间的行并避免迭代

读取 txt 文件的行并组织在 JSON 文件中

用cshell怎么逐行读文件逐行进行处理

Matlab读取txt文件并找出开头相同的行并输出成另一个txt文件

使用 BufferedReader 读取行并检查文件结尾