我正在编写一个 shell 脚本,使用任何通用的 UNIX 命令。我必须检索字符最少的行(包括空格)。最多可以有 20 行左右。
我知道我可以用来head -$L | tail -1 | wc -m
查找 L 行的字符数。问题是,我能想到的唯一方法是手动编写一堆 if 语句,比较值。
示例数据:
seven/7
4for
8 eight?
five!
4for
由于该行字符最少,因此将返回。
就我而言,如果多行的长度最短,则应返回单行。选择哪一个并不重要,只要它是最小长度即可。但我不认为向其他情况下的其他用户显示这两种方式有什么坏处。
答案1
awk
这是打印第一个找到的最小行的解决方案的变体:
awk '
NR==1 || length<len {len=length; line=$0}
END {print line}
'
可以简单地通过一个条件扩展来打印所有最小行:
awk '
length==len {line=line ORS $0}
NR==1 || length<len {len=length; line=$0}
END {print line}'
'
答案2
和sqlite3
:
sqlite3 <<EOT
CREATE TABLE file(line);
.import "data.txt" file
SELECT line FROM file ORDER BY length(line) LIMIT 1;
EOT
答案3
一种 Perl 方式。请注意,如果有多行长度相同且最短的行,则此方法将仅打印其中一行:
perl -lne '$m//=$_; $m=$_ if length()<length($m); END{print $m if $.}' file
解释
perl -lne
:-n
表示“逐行读取输入文件”,-l
导致从每个输入行中删除尾随换行符,并在每个print
调用中添加一个换行符;和-e
是将应用于每一行的脚本。$m//=$_
:除非定义,否则设置$m
为当前行 ($_
) 。$m
该//=
运算符自 Perl 5.10.0 起可用。$m=$_ if length()<length($m)
:如果当前值的长度$m
大于当前行的长度,则将当前行($_
)保存为$m
。END{print $m if $.}
:处理完所有行后,打印$m
最短行的当前值。确保这仅在定义if $.
行号 ( ) 时发生,避免为空白输入打印空行。$.
或者,由于您的文件足够小,可以容纳在内存中,因此您可以执行以下操作:
perl -e '@K=sort{length($a) <=> length($b)}<>; print "$K[0]"' file
解释
@K=sort{length($a) <=> length($b)}<>
:<>
这是一个数组,其元素是文件的行。将sort
根据它们的长度对它们进行排序,并将排序后的行保存为 array@K
。print "$K[0]"
:打印数组的第一个元素@K
:最短的行。
如果您想打印全部最短的线路,你可以使用
perl -e '@K=sort{length($a) <=> length($b)}<>;
print grep {length($_)==length($K[0])}@K; ' file
答案4
我一直喜欢使用纯 shell 脚本的解决方案(无 exec!)。
#!/bin/bash
min=
is_empty_input="yes"
while IFS= read -r a; do
if [ -z "$min" -a "$is_empty_input" = "yes" ] || [ "${#a}" -lt "${#min}" ]; then
min="$a"
fi
is_empty_input="no"
done
if [ -n "$a" ]; then
if [ "$is_empty_input" = "yes" ]; then
min="$a"
is_empty_input="no"
else
[ "${#a}" -lt "${#min}" ] && min="$a"
fi
fi
[ "$is_empty_input" = "no" ] && printf '%s\n' "$min"
笔记:
输入中的 NUL 字节有问题。因此,printf "ab\0\0\ncd\n" | bash this_script
打印ab
而不是cd
.