如何在bash中按制表符分割字符串

45

我正在尝试在bash中拆分一个制表符分隔的字段。

我知道这个答案:如何在shell中拆分字符串并获取最后一个字段

但是这并没有回答关于制表符的问题。

我想要获取制表符之前的字符串部分,所以我正在做这个:

x=`head -1 my-file.txt`
echo ${x%\t*}

但是 \t 是匹配字母 't' 而不是制表符。有什么更好的方法吗?

谢谢


1
如果您正在命令行上编写方便的一行代码,您可以按Ctrl+V,然后按TAB键插入一个制表符。 - user208145
7个回答

76
如果您的文件看起来像这样(以制表符为分隔符):
1st-field   2nd-field

您可以使用cut命令来提取第一个字段(默认情况下操作的是制表符):
$ cut -f1 input
1st-field

如果您正在使用 awk,则无需使用 tail 命令获取最后一行,只需将输入更改为:
1:1st-field     2nd-field
2:1st-field     2nd-field
3:1st-field     2nd-field
4:1st-field     2nd-field
5:1st-field     2nd-field
6:1st-field     2nd-field
7:1st-field     2nd-field
8:1st-field     2nd-field
9:1st-field     2nd-field
10:1st-field    2nd-field

使用awk的解决方案:
$ awk 'END {print $1}' input
10:1st-field

纯 Bash 解决方案:
#!/bin/bash

while read a b;do last=$a; done < input
echo $last

输出:

$ ./tab.sh 
10:1st-field

最后,一个使用 sed 的解决方案
$ sed '$s/\(^[^\t]*\).*$/\1/' input
10:1st-field

这里的$是范围运算符,即仅在最后一行操作。

对于你的原始问题,使用字面制表符,即

x="1st-field    2nd-field"
echo ${x%   *}

输出:

1st-field

19

在参数扩展中使用$'ANSI-C'字符串

$ x=$'abc\tdef\tghi'
$ echo "$s"
abc     def     ghi
$ echo ">>${x%%$'\t'*}<<"
>>abc<<

1
对我来说,这个解决方案使用$'\t'{}参数扩展中,符合OP的要求。我使用它来加速我的脚本,比使用多个管道来cut快76%。 - user208145

10
使用awk命令。
echo $yourfield | awk '{print $1}'

或者说,在你的情况下,是指文件最后一行中的第一个字段。
tail yourfile | awk '{x=$1}END{print x}'

1
谢谢 - 就这样了,只有一个更正:awk -F"\t" '{x=$1}END{print x}' - chaimp
默认的 awk 字段分隔符是空格,其中包括制表符 - 但也许您的应用程序需要缩小它。 - Michael

9
read field1 field2 <<< ${tabDelimitedField}

或者

read field1 field2 <<< $(command_producing_tab_delimited_output)

请在您的代码回答中添加一些解释,以减少 StackOverflow 是一个免费代码编写服务的印象。 - Yunnosch
1
虽然看起来很优雅,但它似乎会按任何空格、空格或制表符进行分割。要仅按制表符拆分,请在命令之前使用 IFS=$'\t' - robrecord

4
有一种简单的方法可以处理制表符分隔的字符串:将其转换为数组。
创建一个带有制表符的字符串(在'\t'解释前加上$):
AAA=$'ABC\tDEF\tGHI'

使用括号将字符串分割为数组:

BBB=($AAA) 

获取任何元素:

echo ${BBB[0]}
ABC
echo ${BBB[1]}
DEF
echo ${BBB[2]}
GHI

2
很遗憾,如果项目可以是零长度字符串,例如AAA=$'a\t\tc',这将无法工作。 - jcupitt
真是个坏消息!:-(谢谢你通知我。但到目前为止,我很幸运,它对我的脚本起作用。 - Denis Capart
它将字符串分割,但在 ${BBB[0]} 中保留了 \t - mateuszb
这似乎在所有的空白字符上分割,不仅限于制表符。 - Katharine Osborne

3

x=first$'\t'second
echo "${x%$'\t'*}"

请在bash手册中查看引用部分。


3
要仅获取“second”,请使用:echo "${x#*$'\t'}"。请参阅man bash中的参数扩展。 - erwin

0

https://stackoverflow.com/users/1815797/gniourf-gniourf 的回答提到了在 bash 中使用内置字段解析的方法,但并没有完整地回答问题。使用 IFS shell 参数来设置输入字段分隔符将完善这个方案,并使得能够在纯 bash 中解析制表符分隔、固定字段数的文件。

echo -e "a\tb\tc\nd\te\tf" > myfile
while IFS='<literaltab>' read f1 f2 f3;do echo "$f1 = $f2 + $f3"; done < myfile

a = b + c
d = e + f

当然,其中的 \t 应该被替换为一个真正的制表符。通常在终端中,使用 Control-V Tab 键可以实现这一点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接