Вы можете добавить длину строки к каждой строке, затем выполнить числовую сортировку и, наконец, вырезать числа.
< your_file awk '{ print length($0), $0; }' | sort -n | cut -f2
Вы видите, что я выполнил сортировку с помощью sort -n
, не выполняя сортировку по нескольким ключам. Честно говоря, мне повезло, что это сработало:
Я не думал, что строки могут начинаться с цифр, и поэтому я ожидал, что sort -n
будет работать, потому что алфавитная и числовая сортировка дают одинаковый результат, если все строки имеют одинаковую длину, как в случае exaclty, потому что мы сортируем по длине строки, которая Добавляю через awk.
Оказывается, все работает, даже если в вашем вводе есть строки, начинающиеся с цифр, причина в том, что sort -n
strcmp
для сравнения целых строкВот некоторые демо:
$ echo -e '3 11\n3 2' | sort -n
3 11
3 2
# the `3 ` on both lines makes them equal for numerical sorting
# but `3 11` comes before `3 2` by `strcmp` before `1` comes before `2`
$ echo -e '3 11\n03 2' | sort -n
03 2
3 11
# the `03 ` vs `3 ` is a numerical tie,
# but `03 2` comes before `3 11` by `strcmp` because `0` comes before `3`
Таким образом, удачная часть заключается в том, что ,
, который я включил в команду awk
, вставляет пробел (на самом деле OFS
), то есть нецифру, тем самым «нарушая» числовую сортировку и позволяя сортировке strcmp
срабатывать (во всех строках, которые сравниваются в данном случае равны численно).
Является ли это поведение POSIX или нет, я не знаю, но я использую GNU coreutils 8.32
's sort
. Обратитесь к этому моему вопросу и этому ответу на Unix для деталей.
awk
может делать все сам, но я думаю, что использование sort
для сортировки более идиоматично (например, использовать sort
для сортировки) и эффективно, как объясняется в комментарии (в конце концов, почему бы вам не ожидать, что sort
является наиболее эффективным инструментом в оболочка для сортировки вещей?).
сортировать более идиоматично.... Думаю, это не совсем аргумент. Однако sort может хорошо справляться с огромными файлами, в то время как с awk все должно уместиться в памяти, если вы хотите использовать встроенный sort
awk; а если зайти так далеко, то я бы даже не использовал awk, а что-то вроде Perl или Ruby, что было бы более подходящим. Так что, в конце концов, это было бы для меня аргументом в пользу использования ... | sort
Кстати, в вашем решении вы должны поместить сортировку по нескольким ключам прямо в пример кода, поскольку ОП запросил, чтобы для ключа равной длины сортировка должна выполняться по алфавиту.
@ user1934428, пожалуйста, посмотрите, нравится ли вам это сейчас. Что касается Ruby и Perl, то я их не знаю, поэтому даже не знаю, насколько они производительны. Думаю, вы могли бы добавить еще один ответ.
в случае ничьей он продолжает использовать алфавитную сортировку на основе остальной части строки: я не думаю, что это правда. На самом деле порядок не указан, и это просто происходит с вашим примером, но в общем случае может сломаться. Чтобы продемонстрировать это, я добавляю опцию -s
, в которой говорится: «Сохранить исходный порядок, если вы не можете принять решение на основе предоставленных критериев сортировки: (echo 3 b; echo 3 a) | sort -n -s
. На самом деле, я думаю, что ваша первоначальная идея явного указания двух ключей сортировки была лучше.
@ user1934428, пожалуйста, рассмотрите мой отредактированный ответ в свете вопроса, который я связал.
Я понимаю! Спасибо, что еще раз прямо указали мне на это.
@ user1934428, спасибо, что подтолкнули меня к расследованию. Как я писал в ответе мне повезло, я не знал этих подробностей которые я знаю сейчас.
Вставьте длину строки с помощью gawk
(заполните нулями до четырех знаков, чтобы сортировка выполнялась правильно), отсортируйте по двум ключам (сначала по длине, затем по первому слову в строке), затем удалите длину:
gawk '{printf "%04d %s\n", length($0), $0}' | sort -k1 -k2 | cut -d' ' -f2-
Если это должен быть bash:
while read -r line; do printf "%04d %s\n" ${#line} "${line}"; done | sort -k1 -k2 | (while read -r len remainder; do echo "${remainder}"; done)
Для GNU awk:
$ gawk '{
a[length()][$0]++ # hash to 2d array
}
END {
PROCINFO["sorted_in"] = "@ind_num_asc" # first sort on length dim
for(i in a) {
PROCINFO["sorted_in"] = "@ind_str_asc" # and then on data dim
for(j in a[i])
for(k=1;k<=a[i][j];k++) # in case there are duplicates
print j
# PROCINFO["sorted_in"] = "@ind_num_asc" # I don t think this is needed?
}
}' file
Выход:
c
aa
ab
aaaa
aaaaaaaaaa
aaaaaaaaaa
Мы призываем вопрошающих показать, что они пытались сделать до сих пор, чтобы решить проблему самостоятельно.