如何使用Bash迭代文本文件的每一行?
使用此脚本:
echo "Start!"
for p in (peptides.txt)
do
echo "${p}"
done
我在屏幕上看到这个输出:
Start!
./runPep.sh: line 3: syntax error near unexpected token `('
./runPep.sh: line 3: `for p in (peptides.txt)'
(后来我想用 $p
做一些更复杂的事情,而不仅仅是输出到屏幕上 . )
环境变量 SHELL 是(来自env):
SHELL=/bin/bash
/bin/bash --version
输出:
GNU bash, version 3.1.17(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
cat /proc/version
输出:
Linux version 2.6.18.2-34-default (geeko@buildhost) (gcc version 4.1.2 20061115 (prerelease) (SUSE Linux)) #1 SMP Mon Nov 27 11:46:27 UTC 2006
文件peptides.txt包含:
RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL
11 回答
还有一些其他答案没有涉及的事情:
从分隔文件中读取
使用进程替换从另一个命令的输出中读取
这种方法优于
command ... | while read -r line; do ...
,因为while循环在当前shell中运行而不是在后者的情况下运行子shell . 请参阅相关文章A variable modified inside a while loop is not remembered .从空分隔输入读取,例如find ... -print0
相关阅读:BashFAQ/020 - How can I find and safely handle file names containing newlines, spaces or both?
一次从多个文件中读取
基于@chepner's回答here:
-u
是一个bash扩展名 . 对于POSIX兼容性,每次调用看起来都像read -r X <&3
.将整个文件读入数组(Bash版本早于4)
如果文件以不完整的行结束(结尾处缺少换行符),则:
将整个文件读入数组(Bash版本4x及更高版本)
要么
然后
More about the shell builtins read and readarray commands - GNU
More about IFS - Wikipedia
BashFAQ/001 - How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?
相关文章:
Creating an array from a text file in Bash
What is the difference between thee approaches to reading a file that has just one line?
Bash while read loop extremely slow compared to cat, why?
这是我的真实例子如何循环另一个程序输出的行,检查子串,从变量中删除双引号,在循环外使用该变量 . 我想很多人迟早会问这些问题 .
在循环外声明变量,设置值并在循环外使用它需要完成<<< "$(...)"语法 . 应用程序需要在当前控制台的上下文中运行 . 命令周围的引号保持输出流的换行符 .
子串的循环匹配然后读取名称=值对,拆分最后=字符的右侧部分,删除第一个引用,删除最后一个引号,我们有一个干净的值在别处使用 .
这并不比其他答案好,但是在没有空格的文件中完成工作的另一种方法(参见注释) . 我发现我经常需要单行来挖掘文本文件中的列表,而无需使用单独的脚本文件 .
这种格式允许我将它全部放在一个命令行中 . 将“echo $ word”部分更改为您想要的任何内容,您可以发出由分号分隔的多个命令 . 以下示例将文件的内容用作您可能编写的其他两个脚本的参数 .
或者,如果您打算像流编辑器一样使用它(学习sed),您可以将输出转储到另一个文件,如下所示 .
我已经使用了上面这些,因为我使用了文本文件,我用它创建了每行一个单词 . (请参阅注释)如果你有空格,你不想拆分你的单词/行,它会有点丑陋,但相同的命令仍然如下工作:
这只是告诉shell只分裂换行符,而不是空格,然后将环境返回到之前的状态 . 此时,您可能需要考虑将所有内容放入shell脚本中,而不是将其全部压缩到一行中 .
祝你好运!
如果您不希望读取被换行符破坏,请使用 -
然后以文件名作为参数运行脚本 .
一种方法是:
正如评论中所指出的,这会产生修剪前导空格,解释反斜杠序列以及如果缺少终止换行符而跳过尾随行的副作用 . 如果这些是问题,你可以这样做:
例外情况下,如果loop body may read from standard input,您可以使用不同的文件描述符打开文件:
这里,10只是一个任意数字(不同于0,1,2) .
假设你有这个文件:
有四个元素会改变许多Bash解决方案读取的文件输出的含义:
空行4;
两行上的前导或尾随空格;
维护各行的含义(即每行是一条记录);
第6行未以CR终止 .
如果希望逐行包含文本文件(包括空行和没有CR的终止行),则必须使用while循环,并且必须对最后一行进行备用测试 .
以下是可能更改文件的方法(与
cat
返回的内容相比):1)丢失最后一行以及前导和尾随空格:
(如果改为
while IFS= read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
,则保留前导和尾随空格,但如果未以CR终止,则仍会丢失最后一行)2)使用
cat
进程替换将一次读取整个文件并且失去了各行的含义:(如果从
$(cat /tmp/test.txt)
中删除"
,则逐字而不是一次读取文件 . 也可能不是预期的...)逐行读取文件并保留所有间距的最强大和最简单的方法是:
如果您想剥离领先和交易空间,请删除
IFS=
部分:(没有终止
\n
的文本文件虽然相当常见,但在POSIX下被视为已损坏 . 如果您可以指望尾随\n
,则while
循环中不需要|| [[ -n $line ]]
. )更多BASH FAQ
Option 1a: while循环:一次一行:输入重定向
Option 1b: while循环:一次一行:
打开文件,从文件描述符中读取(在本例中为文件描述符#4) .
Option 2: For循环:将文件读入单个变量并解析 .
此语法将基于标记之间的任何空白区域解析"lines" . 这仍然有效,因为给定的输入文件行是单字标记 . 如果每行有多个令牌,则此方法不起作用 . 此外,将整个文件读入单个变量对于大文件来说不是一个好策略 .
@Peter:这可能对你有用 -
这将返回输出 -
使用while循环,如下所示:
笔记:
如果未正确设置
IFS
,则会丢失缩进 .You should almost always use the -r option with read.
Don't read lines with for