我正在寻找最简单的方法来打印文件中最长的行。我做了一些谷歌搜索,令人惊讶的是似乎找不到答案。我经常打印文件中最长行的长度,但我不知道如何实际打印最长行。谁能提供打印文件中最长行的解决方案?提前致谢。
ДМИ*_*КОВ 64
cat ./text | awk ' { if ( length > x ) { x = length; y = $0 } }END{ print y }'
Run Code Online (Sandbox Code Playgroud)
UPD:总结评论中的所有建议
awk 'length > max_length { max_length = length; longest_line = $0 } END { print longest_line }' ./text
Run Code Online (Sandbox Code Playgroud)
小智 14
cat filename | awk '{ print length }' | sort -n | tail -1
Run Code Online (Sandbox Code Playgroud)
Vol*_*gel 12
grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt
Run Code Online (Sandbox Code Playgroud)
该命令在没有练习的情况下非常难以阅读,因为它混合了 shell 和 regexp 语法。
为了说明,我将首先使用简化的伪代码。以开头的行##不在 shell 中运行。
这个简化的代码使用文件名 F,为了可读性,省略了引用和部分正则表达式。
该命令有两部分,一个grep- 和一个wc调用:
## grep "^.{$( wc -L F )}$" F
的wc是在以下过程中使用的扩展,$( ... ),所以它之前运行grep。它计算最长线的长度。shell 扩展语法与正则表达式模式语法混合在一起很混乱,所以我将分解过程扩展:
## wc -L F
42
## grep "^.{42}$" F
在这里,进程扩展被替换为它将返回的值,从而创建了grep所使用的命令行。我们现在可以更轻松地阅读正则表达式:它从行的开始 ( ^) 到结束 ( $)完全匹配。它们之间的表达式匹配除换行符之外的任何字符,重复 42 次。组合起来,即正好由 42 个字符组成的行。
现在,回到真正的 shell 命令:grep选项-E( --extended-regexp) 允许不转义{}以提高可读性。选项-m 1( --max-count=1) 使其在找到第一行后停止。的<在wc命令中的文件写入其标准输入,以防止wc从与长度一起打印的文件名。
为了使示例在文件名出现两次时更具可读性,我将为f文件名使用一个变量;$f示例中的每个都可以替换为文件名。
f="file.txt"
Run Code Online (Sandbox Code Playgroud)
显示第一个最长的行- 与最长的行一样长的第一行:
grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"
Run Code Online (Sandbox Code Playgroud)
显示所有最长的行- 所有与最长行一样长的行:
grep -E "^.{$(wc -L <"$f")}\$" "$f"
Run Code Online (Sandbox Code Playgroud)
显示最后最长的行- 与最长行一样长的最后一行:
tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"
Run Code Online (Sandbox Code Playgroud)
显示单个最长的行- 最长的行比所有其他行都长,否则失败:
[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f"
Run Code Online (Sandbox Code Playgroud)
(最后一个命令比其他命令效率更低,因为它重复了完整的 grep 命令。显然应该将其分解,以便将 的输出wc和写入的行grep保存到变量中。
注意,所有最长的行实际上可能是所有行.为了保存在变量中,只需要保留前两行。)
sed -rn "/.{$(<file expand -t1 |wc -L)}/{p;q}" file
Run Code Online (Sandbox Code Playgroud)
这首先读取命令替换内的文件并输出最长行的长度(以前,expand将制表符转换为空格,以克服语义wc -L- 行中的每个制表符都会将行长度加8 而不是 1)。然后在sed表达式中使用这个长度,意思是“找到一行这个长度的字符,打印它,然后退出”。所以这实际上可以是最佳的,因为最长的行靠近文件的顶部,呵呵(感谢提供令人敬畏和建设性的评论)。
另一个,我在 sed 之前就想到了(在 bash 中):
#!/bin/bash
while read -r line; do
(( ${#line} > max )) && max=${#line} && longest="$line"
done
echo "$longest"
Run Code Online (Sandbox Code Playgroud)
这是一个 Perl 解决方案:
perl -e 'while(<>){
$l=length;
$l>$m && do {$c=$_; $m=$l}
} print $c' file.txt
Run Code Online (Sandbox Code Playgroud)
或者,如果您想打印所有最长的行
perl -e 'while(<>){
$l=length;
push @{$k{$l}},$_;
$m=$l if $l>$m;
} print @{$k{$m}}' file.txt
Run Code Online (Sandbox Code Playgroud)
由于我无事可做,我在 625M 文本文件上运行了一些基准测试。令人惊讶的是,我的 Perl 解决方案始终比其他解决方案快。诚然,与公认的awk解决方案的差异很小,但确实存在。显然,打印多行的解决方案速度较慢,所以我按类型排序,从最快到最慢。
只打印最长的一行:
$ time perl -e 'while(<>){
$l=length;
$l>$m && do {$c=$_; $m=$l}
} print $c' file.txt
real 0m3.837s
user 0m3.724s
sys 0m0.096s
$ time awk 'length > max_length { max_length = length; longest_line = $0 }
END { print longest_line }' file.txt
real 0m5.835s
user 0m5.604s
sys 0m0.204s
$ time sed -rn "/.{$(<file.txt expand -t1 |wc -L)}/{p;q}" file.txt
real 2m37.348s
user 2m39.990s
sys 0m1.868s
Run Code Online (Sandbox Code Playgroud)
打印所有最长的行:
$ time perl -e 'while(<>){
$l=length;
push @{$k{$l}},$_;
$m=$l if $l>$m;
} print @{$k{$m}}' file.txt
real 0m9.263s
user 0m8.417s
sys 0m0.760s
$ time awk 'length >x { delete y; x=length }
length==x { y[NR]=$0 } END{ for (z in y) print y[z] }' file.txt
real 0m10.220s
user 0m9.925s
sys 0m0.252s
## This is Chris Down's bash solution
$ time ./a.sh < file.txt
Max line length: 254
Lines matched with that length: 2
real 8m36.975s
user 8m17.495s
sys 0m17.153s
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
58908 次 |
| 最近记录: |