Предположим, у меня есть текстовый файл, как показано ниже
abcd
aaaaaaa
gfgk
hahahahahahhahh
gf
Тогда gf
будет возвращен.Есть хорошие идеи?
Awk отлично подходит для этого:
awk '(NR == 1 || length < length(shortest)) { shortest = $0 } END { print shortest }'
Первая часть устанавливает "самую короткую" переменную для текущей строки, если она является первой строкой или если длина короче самой короткой строки, замеченной ранее. Наконец, последняя часть выводит значение кратчайшего.
Предполагая, что каждая строка содержит «слово» символов,
и мы не против позволить оболочке сделать немного больше работы,
Вот решение AWK.
# Let your text be in `str.txt` awk '{print length($1), $1}' str.txt | sort -nk 1 | head -1 # Output: 2 gf ## Which is the shortest string
Вы можете оптимизировать это, чтобы избежать сортировки с еще большим количеством AWK.
Вы можете изменить это далее, если у вас есть более одного слова в строке.
Также обратите внимание, что если у вас есть несколько самых коротких строк, это даст вам одну из них.
Вы можете сделать еще несколько трюков, чтобы получить их тоже.
BASH FAQ # 1 рассказывает о том, как построчно читать файл. ${#foo}
даст вам длину $foo
. Просто цикл, тестирование каждой строки по очереди.
Решение с использованием sed и сохранением 1-й кратчайшей строки из файла:
sed -e '1h;H;g;s/[^\n]/#/g;s/\(#*\)\n\1/\n/;G;/^\n/s/\n.*\n\(.*\)\n.*/\1/;s/.*\n//;h;$!d' your_file
Чтобы сохранить последнюю короткую строку из файла:
sed -e '1h;G;h;s/[^\n]/#/g;s/\(#*\)\n\1/\n/;G;/^\n/s/\n.*\n\(.*\)\n.*/\1/;s/.*\n//;h;$!d' your_file
Ниже представлен вариант первой кратчайшей строки в форме файла сценария sed, который можно запустить с помощью sed -f script your_file
:
# The hold space will contain the shortest line at the beginning and the ending of each cycle.
# The 1st line is the shortest, so put it in the hold space so an empty line will not be returned.
1h
# Append the current line to the shortest so far, remember these 2 lines in the hold space, and take a copy in the pattern space to work on them.
H;g
# Replace all chars by #.
s/[^\n]/#/g
# Delete the same number of # before and after the line delimiter.
s/\(#*\)\n\1/\n/
# Append the 2 lines remembered in the hold space to the pattern space.
G
# If the hold space begin by a '\n', the current line was shorter, so keep it.
/^\n/s/\n.*\n\(.*\)\n.*/\1/
# Else, the previous line was shorter, so keep it.
s/.*\n//
# Remember shortest in hold space.
h
# If last line, print it (delete everything else).
$!d
Вот мое довольно неуклюжее предложение с использованием Perl:
grep . file | perl -E '@a=<>; @s = sort {length $a <=> length $b}@a; say $s[0] . "Line $."; '
Несколько проще: perl -ne '$ l = $ _ if $. == 1; $ l = $ _, если длина ($ ) <длина ($ l); END {print $ l;} 'file ### кратчайший perl -ne' $ l = $ if $. == 1; $ l = $ _ if length ($ _)> length ($ l); END {print $ l;} 'file ### longest
grep. файл | perl -ne '$ l = $ _ if $. == 1; $ l = $ _, если длина ($ _) <длина ($ l); END {print $ l;} '## кратчайшее удаление возможных пустых строк
grep. файл | perl -ne '$ l = $ _ if $. == 1; $ l = $ _, если длина ($ _) <длина ($ l); END {print $ l;} '## самое длинное удаление возможных пустых строк