如何在bash脚本中获取文件的第一行?

374

我需要将文件的第一行放入一个bash变量中。我想可以使用grep命令,但是否有任何方法可以限制行数?

8个回答

577

head 命令从一个文件中获取前几行数据,-n 参数可以用来指定需要提取的行数:

line=$(head -n 1 filename)

8
与“read”方法相比,开销显著更大。“$()”会派生出一个子shell,使用外部命令(任何外部命令)意味着您正在调用“execve()”,调用链接器和加载器(如果它正在使用共享库,这通常是情况),等等。 - Charles Duffy
2
它甚至可以更短: line="$(head -1 FILENAME)" - nikolay
3
也可以这样写:line=$(head -1 FILENAME) - Shai Alon
1
反引号 head... 周围的符号是否像 $() 一样打开一个子shell? - Jaime Hablutzel
1
@JaimeHablutzel 是的,它们是同一件事,尽管我个人认为 $() 语法更容易看到,并且重视清晰度而不是绝对简洁。http://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html - Joseph Sikorski
显示剩余4条评论

94

要使用bash读取第一行,可以使用read语句。例如:

read -r firstline<file

firstline将是您的变量(无需分配给其他变量)


1
@sorin,“cat ... | read VAR” 在大多数 shell 中都会失败(据我所知,除了 zsh),因为管道中的每个组件将在单独的子 shell 中运行。这意味着 $VAR 将在子 shell 中设置(该子 shell 一旦管道执行完成就会停止存在),而不是在调用 shell 中设置。您可以通过 read VAR <<EOF\n$(cat ...)\nEOF(其中每个 \n 表示一个换行符)来避免这种情况。 - zrajm
@sorin,“cat”是纯粹的开销;无论如何,使用“read -r var <file”比“cat file | read”更有效率,即使后者不因BashFAQ#24中描述的原因而失败。 - Charles Duffy
如果你运行的程序比 cat 更复杂,那么可以使用 read -r var < <(otherprog ...) - Charles Duffy
如果您的文件中使用了'<',则会出现“语法错误,附近的令牌`newline'”失败,请参见此处:https://www.delftstack.com/howto/linux/bash-solve-syntax-error-near-unexpected-token-newline/。 - Ismoh
就性能而言,使用read比head或任何其他命令(如awk、sed)更好。这是因为read是一个内部命令。 - Saran Raj

43

这样就足够了,并且将filename的第一行存储到变量$line中:

read -r line < filename

对于此问题,我也喜欢使用awk

awk 'NR==1 {print; exit}' file

使用var=$(command)语法来存储行本身。在这种情况下,line=$(awk 'NR==1 {print; exit}' file)

甚至可以使用sed

sed -n '1p' file

使用等效的命令 line=$(sed -n '1p' file)


看一个示例,当我们使用seq 10这个命令时,可以将其作为read的输入,即一个从1到10的数字序列:

$ read -r line < <(seq 10) 
$ echo "$line"
1

$ line=$(awk 'NR==1 {print; exit}' <(seq 10))
$ echo "$line"
1

2
sed '1!d;q'(或 sed -n '1p;q')将模仿您的 awk 逻辑并防止进一步读取文件。因为我们只想要第一行,所以我们可以使用 sed qawk '1;{exit}' 或甚至是 grep -m1 ^(代码更少,但本质逻辑相同)。 (这不是对投票下降的询问的回复。) - Adam Katz
1
@AdamKatz,非常好的一组方法,谢谢!我觉得使用grep的那个很聪明。当然,我们也可以使用head -n 1 file - fedorqui
是的, head -n1 会更快(二进制文件较小,加载更快),而 read 是最快的(没有二进制文件需要加载,因为它是内置命令)。当我只需要打印第一行时,我特别喜欢使用 grep -m1 --color . ,因为它可以给这行加上颜色,非常适合用于表头。 - Adam Katz

17

只需将源文件中的第一个列表使用echo命令输出到目标文件中即可。

echo $(head -n 1 source.txt) > target.txt

7
执行命令 head -n 1 source.txt > target.txt 将达到完全相同的效果。 - YoYo

16
line=$(head -1 file)

会正常工作。 (如前面的答案)。 但是

line=$(read -r FIRSTLINE < filename)

使用内置的Bash命令read将稍微更快。


24
第二种方法按原文写法无法实现,因为read不会打印任何内容(所以line最终为空),而且在子 shell 中执行(所以FIRSTLINE被设置为第一行,但仅在子 shell 中有效,因此之后不可用)。解决方法:只需使用 read -r line <filename> - Gordon Davisson
2
line=$(read -r < filename ;printf %s "$REPLY") 应该可以工作 或者 line=$(read -r < <(some command); printf %s "$REPLY") - marinara

6

这个问题并没有询问哪一个是最快的,但是作为对 sed 答案的补充,-n '1p' 在处理大文件时性能较差,因为模式空间仍然会被扫描。出于好奇,我发现 'head' 稍微比 sed 更快:

# best:
head -n1 $bigfile >/dev/null

# a bit slower than head (I saw about 10% difference):
sed '1q' $bigfile >/dev/null

# VERY slow:
sed -n '1p' $bigfile >/dev/null

0

只读取文件的第一行并将其存储到变量中:

read var < file

echo $var # print only the first line of 'file'

这如何补充@fedorqui在下面的答案中所说的内容? - Consti P
我的答案是实现目标的简单方法... - Grégori Fernandes de Lima
1
但是链接的答案包括了这个片段和更多内容,所以你并没有添加任何价值,只是在重申。 - Consti P
与@ConstiP的观点相同,请删除答案或在答案中说明为什么您认为您的答案提供了新价值 - 可能是因为它没有使用“-r”标志。 - Timo

0
你可以使用以下语法简单地获取任何你想要的行:
n=4;
line=$(head -n $n file | tail -n 1) 

这个工作的方式首先是使用head -n $n命令列出文件中的前n行,然后将head命令的输出传递给tail命令,以提取最后一行。

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