linux - Bash循环只读最后一行

标签 linux bash shell for-loop awk

我在尝试使用 while 循环和 awk 提取多行冒号后面的数据时遇到问题.

这是我的数据结构:

Identifiers:BioSample:SAMD00019077
Identifiers:BioSample:SAMD00019076
Identifiers:BioSample:SAMD00019075
Identifiers:BioSample:SAMD00019074
Identifiers:BioSample:SAMD00019073
Identifiers:BioSample:SAMD00019072
Identifiers:BioSample:SAMD00019071;SRA:DRS051563
Identifiers:BioSample:SAMD00019070;SRA:DRS051562
Identifiers:BioSample:SAMD00019069;SRA:DRS051561
...
Identifiers:BioSample:SAMD00019005;SRA:DRS051497
Identifiers:BioSample:SAMD00015713;SRA:DRS012785

我想要得到的是BioSample ID ,类似于 SAMD00019077 .

我试过的脚本:

  1. while read line ; do echo $line | awk -F':' '{print $3}' > 1.tmp2 ; done < 1.tmp
  2. for line in猫 1.tmp ; do echo $line | awk -F':' '{print $3}' > 1.tmp2 ; done
  3. for line in猫 1.tmp ; do echo $line | awk -F: '{print $3 > "1.tmp2"}' ; done

他们只给了Biosample ID最后一行:

$ while read line ; do echo $line | 
  awk -F':' '{print $3}' > 1.tmp2 ; done < 1.tmp
$ head 1.tmp2
SAMD00015713;SRA

我阅读了此处的帖子,看起来我的问题与 stdin 有关, stdoutstderr .

bash read loop only reading first line of input variable

bash while loop read only one line

我试过的解决方案,它给出了 1 行的结果

$ exec 3<&1
$ exec 1<&2
$ while read line ; do echo $line |  
  awk -F':' '{print $3}' > 1.tmp2 ; done< 1.tmp
$ head 1.tmp2
SAMD00015713;SRA
$ exec 1<&3 3<&-

我也试过exec < 1.tmp将文件指向 stdin但它会导致错误。

我发现这些脚本对我来说效果很好。但我真的很想知道为什么我上面尝试的脚本失败了。

cat 1.tmp | awk -F: '{print $3}' | head

awk -F: '{print $3}' 1.tmp | head

最佳答案

首先,awk 具有循环遍历行的能力,字段分隔符可以是正则表达式。

因此,您的脚本可以简化为这种优化格式:

awk -F'[;:]' '{print $3}' 1.tmp > 1.tmp2

这是您可以使用的优化格式。

话虽如此,您可能想知道脚本中出了什么问题。

while read line ; do echo $line | awk -F':' '{print $3}' > 1.tmp2 ; done < 1.tmp
                                                         ^ here

上面标记的>就是重定向操作符。 它将命令的标准输出(在本例中为 awk)写入指定的文件。它不追加,而是覆盖。 因此,在循环的每次迭代中,都会清除文件并将命令的输出写入其中。因此它只留下最后一个条目。

要解决这个问题,您可以使用附加重定向:>>>

while read line ; do echo $line | awk -F':' '{print $3}' >> 1.tmp2 ; done < 1.tmp

现在,有一个警告。如果文件原本不是空的怎么办?此循环将附加到文件,而不先清除文件。要解决此问题,您可以先使用以下命令清除文件:

>1.tmp2; while read line ; do echo $line | awk -F':' '{print $3}' >> 1.tmp2 ; done < 1.tmp

但是,如果我们确定循环产生的所有标准输出都需要进入文件,您可以简单地将重定向移出循环。这样,shell 就不必一直打开和关闭文件描述符。

while read line ; do echo $line | awk -F':' '{print $3}'; done < 1.tmp > 1.tmp2

请注意,这些选项未经优化,但仍然有效。优化的选项是让 awk 本身按照答案的第一个片段中提到的那样进行逐行处理。

关于linux - Bash循环只读最后一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57423117/

相关文章:

bash - 如何删除 "TERM environment variable not set"

linux - 将参数传递给要在 ssh 中执行的 shell 脚本

shell - 将具有分号 (';' ) 的值分配给 bash 中的变量

javascript - Nodejs && JSON : select value by key

c++ - 为什么挂钟比 cpu 用户/内核时间高很多

git - 推送到 git 后重启 PlayFramework 2 实例的脚本 bash?

c# - 检测 Gtk 和 Mono 中的 TextView 变化

python - 循环和子流程中的列表,标准输出

linux - 用于区分 linux 中的服务帐户和用户帐户的脚本

c++ - 如何检查给定的 UTC 偏移量是否启用了夏令时?