如何使bash内置“读取”忽略注释或空行?

Wil*_*ard 6 bash shell-script read

(为简单起见,我假设要读取的文件是第一个参数 - $1。)

我可以在外部做我想做的事:

tempfile=$(mktemp)
awk '/^#/ {next}; NF == 0 {next}; {print}' "$1" > $tempfile
while read var1 var2 var3 var4 < $tempfile; do
  # stuff with var1, etc.
done
Run Code Online (Sandbox Code Playgroud)

但是,awk每次解析配置文件时都需要调用似乎很荒谬。有没有办法read忽略文件中的注释行或空白行,而没有外部二进制文件/潜在的性能问题?


到目前为止的答案非常有帮助!澄清一下,我不想使用临时文件,但我确实从文件中读取配置,而不是从标准中读取配置。我很清楚在调用脚本时可以使用输入重定向,但是由于各种原因在我的情况下不起作用。

我想对要读取的输入进行软编码,例如:

configfile="/opt/myconfigfile.txt"
[ $# -gt 0 ] && [ -r "$1" ] && configfile="$1"

while read var1 var2 var3 var4 < "$configfile" ; do
  ...
Run Code Online (Sandbox Code Playgroud)

但是当我尝试这个时,它只是configfile一遍又一遍地读取第一行,直到我终止进程。

也许这应该是它自己的问题......但它可能与我正在做的事情不同。我的错误在哪里?

cas*_*cas 6

您不需要临时文件来执行此操作,并且 sed(或 awk)在注释处理方面比 shell case 语句灵活得多。

例如:

configfile='/opt/myconfigfile.txt'
[ $# -gt 0 ] && [ -r "$1" ] && configfile="$1"

sed -e 's/[[:space:]]*#.*// ; /^[[:space:]]*$/d' "$configfile" |
    while read var1 var2 var3 var4; do
      # stuff with var1, etc.
    done

# Note: var1 etc are not available to the script at this
# point. They are only available in the sub-shell running
# the while loop, and go away when that sub-shell ends.
Run Code Online (Sandbox Code Playgroud)

这会删除注释(带或不带前导空格)并从输入中删除空行,然后再将其输送到 while 循环中。它单独处理行上的注释以及附加到行尾的注释:

# full-line comment
# var1 var2 var3 var4
abc 123 xyz def # comment here
Run Code Online (Sandbox Code Playgroud)

像这样的呼叫sedawk任务并不“荒谬”,而是完全正常的。这就是这些工具的用途。至于性能,我敢打赌,除了非常小的输入文件之外,该sed版本会快得多。管道传输sed有一些启动开销,但运行速度非常快,而 shell 则很慢。


2022年5月3日更新:

请注意,当 while 循环结束时,在 while read 循环中设置的变量(var1、var2、var3 等)将“超出范围”。只能在 while 循环内部使用。while 循环正在子 shell 中运行,因为配置文件通过管道传输到其中。当该子 shell 死亡时,它的环境也随之消失 - 并且子进程无法更改其父进程的环境。

如果您希望变量在 while 循环后保留其值,则需要避免使用管道。例如,使用输入重定向 ( <) 和进程替换( <(...)):

while read var1 var2 var3 var4; do
  # stuff with var1, etc.
done < <(sed -e 's/[[:space:]]*#.*// ; /^[[:space:]]*$/d' "$configfile")

# remainder of script can use var1 etc if and as needed.
Run Code Online (Sandbox Code Playgroud)

使用此进程替换版本,while 循环在父 shell 中运行,并且sed脚本作为子进程运行(其输出重定向到 while 循环)。sed 及其环境在完成后消失,而运行 while 循环的 shell 保留循环创建/更改的变量。