Сортировка по последнему полю строки - PullRequest
34 голосов
/ 11 июля 2010

Какой самый простой способ сортировки списка строк, сортировка по последнему полю каждой строки?Каждая строка может иметь переменное количество полей.

Что-то вроде

sort -k -1

- это то, что я хочу, но sort (1) не принимает отрицательные числа для выбора полей с конца вместоначало.

Я также хотел бы иметь возможность выбрать разделитель полей.

Редактировать: Чтобы добавить некоторую специфичность к вопросу: список, который я хочу отсортировать, представляет собой списокмаршруты.Имена путей могут быть произвольной глубины, поэтому переменное количество полей.Я хочу отсортировать компонент имени файла.

Эта дополнительная информация может изменить способ манипулирования строкой для извлечения последнего поля (можно использовать basename (1)), но не меняет требований к сортировке.

например,

/a/b/c/10-foo
/a/b/c/20-bar
/a/b/c/50-baz
/a/d/30-bob
/a/e/f/g/h/01-do-this-first
/a/e/f/g/h/99-local

Я хочу, чтобы этот список был отсортирован по именам файлов, которые начинаются с цифр, указывающих порядок чтения файлов.

Я добавил свой ответ, ниже которогокак я сейчас это делаю.Я надеялся, что есть более простой способ - возможно, другая утилита сортировки - возможно, без необходимости манипулировать данными.

Ответы [ 11 ]

13 голосов
/ 28 марта 2013
awk '{print $NF,$0}' file | sort | cut -f2- -d' '

По сути, эта команда выполняет:

  1. Повтор последнего поля в начале, разделенный пробелом (по умолчанию OFS)
  2. Сортировка, разрешение дублированных имен файлов с использованиемполный путь ($ 0) для сортировки
  3. Вырезать повторное первое поле, f2- означает от второго поля до последнего
12 голосов
/ 12 июля 2010

Вот командная строка Perl (обратите внимание, что ваша оболочка может потребовать от вас $ s):

perl -e "print sort {(split '/', $a)[-1] <=> (split '/', $b)[-1]} <>"

Просто перенаправьте список в него или, если список находится в файле, поместите имя файла в конец командной строки.

Обратите внимание, что этот скрипт фактически не изменяет данные, поэтому вам не нужно быть осторожным с тем, какой разделитель вы используете.

Вот пример вывода:

>perl -e "print sort {(split '/', $a)[-1] <=> (split '/', $b)[-1]} " files.txt
/a/e/f/g/h/01-do-this-first
/a/b/c/10-foo
/a/b/c/20-bar
/a/d/30-bob
/a/b/c/50-baz
/a/e/f/g/h/99-local
6 голосов
/ 11 июля 2010

как то так

awk '{print $NF"|"$0}' file | sort -t"|" -k1 | awk -F"|" '{print $NF }'
3 голосов
/ 11 июля 2010

Однострочный в perl для изменения порядка полей в строке:

perl -lne 'print join " ", reverse split / /'

Вы можете использовать его один раз, направить вывод для сортировки, затем направить его обратно и вы получитето, что ты хочешь.Вы можете изменить / / на / +/, чтобы он сжимал пробелы.И вы, конечно, можете использовать любое регулярное выражение, которое хотите разбить на строки.

2 голосов
/ 11 июля 2010

Я думаю, что единственным решением было бы использовать awk:

  1. Поместите последнее поле вперед, используя awk.
  2. Сортировка строк.
  3. Поместите первое поле в конец снова.
1 голос
/ 12 июля 2010

Замените последний разделитель в строке другим разделителем, который иначе не отображается в списке, выполните сортировку по второму полю, используя этот другой разделитель в качестве разделителя sort (1), а затем отмените изменение разделителя.

delim=/
new_delim=" "
cat $list \
| sed "s|\(.*\)$delim|\1$new_delim|" \
| sort -t"$new_delim" -k 2,2 \
| sed "s|$new_delim|$delim|"

Проблема в том, что нужно знать, какой разделитель использовать, который не отображается в списке. Вы можете сделать несколько проходов по списку, а затем выполнить поиск последовательности потенциальных разделителей, но все это довольно неприятно - особенно когда понятие «сортировка по последнему полю строки» так просто выражено, а решение - нет.

Редактирование: один безопасный разделитель для $ new_delim - NUL, поскольку он не может появляться в именах файлов, но я не знаю, как поместить символ NUL в сценарий оболочки Bourne / POSIX (не bash), а также использовать sort и sed правильно с этим справится.

0 голосов
/ 13 апреля 2019
| sed "s#(.*)/#\1"\\$'\x7F'\# \
| sort -t\\$'\x7F' -k2,2 \
| sed s\#\\$'\x7F'"#/#"

Еще хуже, чем простые отрицательные индексы полей для sort (1), но использование символа DEL в качестве разделителя в этом случае не должно вызывать никаких проблем.

Мне также нравится, насколько это симметрично.

0 голосов
/ 27 мая 2018

Вот версия Python oneliner, обратите внимание, что предполагается, что поле является целым числом, вы можете изменить его при необходимости.

echo file.txt | python3 -c 'import sys; list(map(sys.stdout.write, sorted(sys.stdin, key=lambda x: int(x.rsplit(" ", 1)[-1]))))'
0 голосов
/ 08 октября 2017

Я хочу, чтобы этот список сортировался по именам файлов, которые начинаются с цифр с указанием порядка чтения файлов.

find . | sed 's#.*/##' | sort

sed заменяет все части списка результатов, заканчивающиеся косыми чертами. имена файлов - то, что осталось, и вы сортируете по этому.

0 голосов
/ 11 июля 2010
#!/usr/bin/ruby

f = ARGF.read
lines = f.lines

broken = lines.map {|l| l.split(/:/) }

sorted = broken.sort {|a, b|
    a[-1] <=> b[-1]
}

fixed = sorted.map {|s| s.join(":") }

puts fixed

Если все ответы связаны с perl или awk, то все это может быть решено на языке сценариев.(Между прочим, я сначала попробовал в Perl и быстро вспомнил, что мне не нравятся списки списков Perl. Я хотел бы увидеть версию Perl-гуру.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...