我有以下格式的文件,它是制表符分隔的
a k testis adult male 8 week rRNA
b k testis adult male 8 week rRNA
c k testis adult male 8 week rRNA
Run Code Online (Sandbox Code Playgroud)
我想在每一行上做一些操作,所以我使用了一个 while 循环。我想在选项卡上拆分每一行,然后存储让我们说第 6 列8 week
的变量。我正在使用此代码,但无法获得我想要的
while read -r line; do tmp=(${line///}); col6=${tmp[5]}; echo "$col6"; done < file.txt
Run Code Online (Sandbox Code Playgroud)
这给了我8
而不是8 week
。8 周在 8 和周之间有一个空格,因此我想在选项卡上拆分该行。
ilk*_*chu 15
数组分配tmp=(${line///})
将值拆分为IFS
包含的任何字符,默认情况下包括制表符、空格和换行符。(我看不到空替换的作用。)要仅在选项卡上拆分,请设置IFS
为:
foo=$'a\tk\testis\tadult\tmale\t8 week\tRNA'
IFS=$'\t'
tmp=($foo)
echo "${tmp[5]}"
Run Code Online (Sandbox Code Playgroud)
虽然这仍然留下通配符是一个问题,因为你已经在使用while read
,你可以使用read -a tmp
(Bash中只,更换-a
与-A
使用的ksh / zsh的/佳日),它分裂基础上的输入线IFS
,并将所产生的领域的元素命名数组:
$ while IFS=$'\t' read -r -a tmp ; do
echo "${tmp[5]}"
done <<< $'a\tk\testis\tadult\tmale\t8 week\tRNA'
Run Code Online (Sandbox Code Playgroud)
那打印8 week
. 这样做的另一个好处是,更改IFS
仅在 的持续时间内有效read
,而不对脚本的其余部分有效。
但是请注意,read
使用制表符作为分隔符时会删除空字段。在 中zsh
,您可以替换IFS=$'\t'
为IFS=$'\t\t'
以阻止这种情况发生。
当然,如果我们知道字段的数量/含义,我们可以read
将它们拆分为单独的命名变量:
... IFS=$'\t' read -r col1 col2 col3 ...
Run Code Online (Sandbox Code Playgroud)
或者,如果您只想打印那一列,请使用cut
:
cut -d$'\t' -f 6 < file.txt
Run Code Online (Sandbox Code Playgroud)
如果您有空列,cut -d$'\t'
并且IFS=$'\t'
对它们有不同的行为。Cut 会将每个单独的选项卡视为不同的分隔符,而read
将连续的选项卡视为单个分隔符。也就是说,字符串foo<tab><tab>bar
将被读取为两列read
,但被读取为三列cut
。
您不能为制表符更改此设置,但打印字符始终被识别为不同的分隔符,因此您可以将制表符更改为某个未出现在数据中的字符,然后将其用作分隔符,例如... | tr '\t' : | IFS=: read -r -a tmp
左右。