Linux/UNIX:Bash 逐行读取文件
当使用 Bash、KSH 或您选择的任何其他 shell 时,您可以使用 while..do..done bash 循环在 Linux、OSX、*BSD 或类 Unix 系统上逐行读取文件。
教程详细信息 | |
---|---|
难度等级 | 简单的 |
Root 权限 | 不 |
要求 | Linux 终端 |
类别 | Linux shell 脚本 |
先决条件 | Bash/ksh/zsh/tcsh |
操作系统兼容性 | BSD • Linux • macOS • Unix • WSL |
预计阅读时间 | 4 分钟 |
语法:在 Bash Unix 和 Linux shell 上逐行读取文件
bash、ksh、zsh 和所有其他 shell 逐行读取文件的语法如下:
- 当读取 -r 行时;执行命令;完成 < 输入.文件
- 传递给 read 命令的-r选项可防止反斜杠转义被解释。
- 在读取命令之前添加IFS=选项,以防止修剪前导/尾随空格。
- 当 IFS=读取 -r 行时;在 $line 上执行 COMMAND_;完成 < input.file
如何在 Bash 中逐行读取文件
以下是更加人性化、可读的语法:
#!/bin/bash input="/path/to/txt/file" while IFS= read -r line do echo "$line" done < "$input"
输入文件 ( $input) 是您需要通过 read 命令使用的文件的名称。read 命令逐行读取文件,并将每行分配给$linebash shell 变量。从文件读取所有行后,bash while 循环将停止。内部字段分隔符 (IFS) 设置为空字符串以避免出现空格问题。这是一个故障安全功能。该-r选项用于不允许反斜杠转义任何字符。请注意,当在 read 命令前存在 IFS= 时,read 命令会通过删除所有前导和尾随空格字符(例如空格和制表符)来修改每个输入行。但是,如果您想要修剪,请不要在 read 命令前设置 IFS=。例如:
#!/bin/bash input="/path/to/txt/file" ###################################### # $IFS removed to allow the trimming # ##################################### while read -r line do echo "$line" done < "$input"
如何使用命令/进程替换逐行读取文件
进程或命令替换无非就是运行 shell 命令并将其输出存储到变量或将其传递给另一个命令。语法如下:
while IFS= read -r line do ## take some action on $line echo "$line" done < < (command)
在此示例中,运行 ps 命令aux列出所有进程,然后打印它们或根据需要采取特定操作:
while IFS= read -r line do ## take some action on $line echo "$line" done < <(ps aux)
使用这里的字符串
这里的字符串就像这里的文档一样。我们可以用它将数据提供给我们的bash while 循环。例如:
while IFS= read -r line do # take action on $line # echo "$line" done <<< $(command) while IFS= read -r line do # take action on $line # echo "$line" done <<< $(ps aux)
以下是从 CLI 清除或清除 Cloudflare URL/图像的示例 shell 脚本:
## shell script to purge urls from Cloudflare ## t="10" I="/home/vivek/.data/tags.deleted.410" # input file url="" while IFS= read -r line do url="$url $line" done <<<"$(tail -${t} ${I})" [ "$url" != "" ] && ~/bin/cloudflare.purge.urls.sh "$url"
如何在读取命令中使用文件描述符 (FD)
语法很简单:
input="/path/to/file" while IFS= read -r -uN line do # do something on $line echo "$line" done N< $input
下面是一个示例脚本,它从文件描述符 FD # 13 读取,而不是从键盘或文件等标准输入读取:
while IFS= read -r -u13 line do echo "$line" done 13<"${input}"
演示如何逐行读取文件的示例
让我们看一些有关此主题的示例:
#!/bin/ksh file="/home/vivek/data.txt" while IFS= read line do # display $line or do something with $line echo "$line" done <"$file"
使用 bash shell 的相同示例:
#!/bin/bash file="/home/vivek/data.txt" while IFS= read -r line do # display $line or do somthing with $line printf '%s\n' "$line" done <"$file"
逐个字段读取输入文件行
你也可以按字段读取。例如,/etc/passwd共有 7 个字段,我们可以按如下方式逐个读取它们。首先,让我们使用cat 命令或 more 命令查看文件:
cat /etc/passwd more /etc/passwd
示例文件:
root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin .... .. .... vivek:x:1000:1000:vivek,,,:/home/vivek:/bin/bash systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false nvidia-persistenced:x:127:134:NVIDIA Persistence Daemon,,,:/nonexistent:/usr/sbin/nologin sshd:x:128:65534::/run/sshd:/usr/sbin/nologin
在此示例中,我将通过设置要读取的附加变量来对每行中的各个字段进行操作,例如 f1、f2 等:
#!/bin/bash file="/etc/passwd" # # Each input line divided into seven fields separated by a colon (:) character # while IFS=: read -r f1 f2 f3 f4 f5 f6 f7 do # display fields using f1, f2,..,f7 printf 'Username: %s, Shell: %s, Home Dir: %s\n' "$f1" "$f7" "$f6" done <"$file"
图 01:Bash shell 脚本-逐行读取文件演示输出
Bash 脚本:逐行读取文本文件以创建 pdf 文件
我的输入文件如下(faq.txt):
4|http://www.example.com/faq/mysql-user-creation/|Mysql User Creation: Setting Up a New MySQL User Account 4096|http://www.example.com/faq/ksh-korn-shell/|What is UNIX / Linux Korn Shell? 4101|http://www.example.com/faq/what-is-posix-shell/|What Is POSIX Shell? 17267|http://www.example.com/faq/linux-check-battery-status/|Linux: Check Battery Status Command 17245|http://www.example.com/faq/restarting-ntp-service-on-linux/|Linux Restart NTPD Service Command 17183|http://www.example.com/faq/ubuntu-linux-determine-your-ip-address/|Ubuntu Linux: Determine Your IP Address 17172|http://www.example.com/faq/determine-ip-address-of-linux-server/|HowTo: Determine an IP Address My Linux Server 16510|http://www.example.com/faq/unix-linux-restart-php-service-command/|Linux / Unix: Restart PHP Service Command 8292|http://www.example.com/faq/mounting-harddisks-in-freebsd-with-mount-command/|FreeBSD: Mount Hard Drive / Disk Command 8190|http://www.example.com/faq/rebooting-solaris-unix-server/|Reboot a Solaris UNIX System
我的bash脚本:
#!/bin/bash # Usage: Create pdf files from input (wrapper script) # Author: Vivek Gite <Www.example.com> under GPL v2.x+ #--------------------------------------------------------- #Input file _db="/tmp/wordpress/faq.txt" #Output location o="/var/www/prviate/pdf/faq" _writer="~/bin/py/pdfwriter.py" # If file exists if [[ -f "$_db" ]] then # read it while IFS='|' read -r pdfid pdfurl pdftitle do local pdf="$o/$pdfid.pdf" echo "Creating $pdf file ..." #Genrate pdf file $_writer --quiet --footer-spacing 2 \ --footer-left "example is GIT UL++++ W+++ C++++ M+ e+++ d-" \ --footer-right "Page [page] of [toPage]" --footer-line \ --footer-font-size 7 --print-media-type "$pdfurl" "$pdf" done <"$_db" fi
从 bash shell 变量读取
假设你想要 Debian 或 Ubuntu Linux 上所有已安装的 php 包的列表,请输入:
# My input source is the contents of a variable called $list # list=$(dpkg --list php\* | awk '/ii/{print $2}') printf '%s\n' "$list"
示例输出:
php-pear php5-cli php5-common php5-fpm php5-gd php5-json php5-memcache php5-mysql php5-readline php5-suhosin-extension
您现在可以从 $list 读取并安装该包:
#!/bin/bash # BASH can iterate over $list variable using a "here string" # while IFS= read -r pkg do printf 'Installing php package %s...\n' "$pkg" /usr/bin/apt-get -qq install $pkg done <<< "$list" printf '*** Do not forget to run php5enmod and restart the server (httpd or php5-fpm) ***\n'
示例输出:
Installing php package php-pear... Installing php package php5-cli... Installing php package php5-common... Installing php package php5-fpm... Installing php package php5-gd... Installing php package php5-json... Installing php package php5-memcache... Installing php package php5-mysql... Installing php package php5-readline... Installing php package php5-suhosin-extension... *** Do not forget to run php5enmod and restart the server (httpd or php5-fpm) ***
结论
本页解释了如何在 bash shell 脚本中逐行读取文件。使用 man 命令或 help 命令查看以下文档:
$ man bash
$ man ksh
$ help read
选项 | 描述 |
---|---|
-a array | 将读取的字分配给数组变量 ARRAY 的连续索引(从零开始)。 |
-d delim | 继续,直到读到 DELIM 的第一个字符,而不是换行符。 |
e | 使用 Readline 获取该行。 |
-i text | 使用 TEXT 作为 Readline 的初始文本。 |
-n nchars | 读取 NCHARS 个字符后返回,而不是等待换行符,但如果在分隔符之前读取的字符少于 NCHARS 个,则遵守分隔符。 |
-N nchars | 仅在读取 NCHARS 个字符后返回,除非遇到 EOF 或读取超时,忽略任何分隔符。 |
-p prompt | 在尝试读取之前,输出不带尾随换行符的字符串 PROMPT。 |
-r | 不允许使用反斜杠转义任何字符。 |
-s | 不要回显来自终端的输入。 |
-t timeout | 如果在 TIMEOUT 秒内未读取完整的一行输入,则超时并返回失败。TMOUT 变量的值是默认超时。TIMEOUT 可能是小数。如果 TIMEOUT 为 0,则 read 立即返回,而不尝试读取任何数据,仅当指定的文件描述符上有输入时才返回成功。如果超出超时,退出状态大于 128。 |
-u fd | 从文件描述符 FD 读取而不是从标准输入读取。 |