Как отсортировать второй столбец по алфавиту, а затем по номерам в сценарии оболочки? - PullRequest
0 голосов
/ 04 ноября 2018

У меня есть текстовый файл, как показано ниже:

info.txt

files-550519470 19h
files-1662192679 1d
files-247106034 1d
files-1986982365 2d
files-464153317 12m
files-739420408 3d
files-77614277 3m
files-374059185 4d
files-909323637 4d
files-101830442 5d
files-1270496134 5d
files-1797797160 6d
files-812888216 7d
files-118869238 7h

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

 files-812888216 7d
 files-1797797160 6d
 files-101830442 5d
 files-101830442 5d
 files-1270496134 5d
 files-374059185 4d
 files-909323637 4d
 files-374059185 4d
 files-909323637 4d
 files-739420408 3d
 files-1986982365 2d
 files-1662192679 1d
 files-247106034 1d
 files-550519470 19h
 files-118869238 7h
 files-464153317 12m
 files-77614277 3m

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

 sort -r -nk2 info.txt

Ответы [ 2 ]

0 голосов
/ 06 ноября 2018

Использование Декорирование, Сортировка, Декорирование Выкройка:

$ sort -t $'-' -k 2 file | 
sed -E 's/(.*) ([[:digit:]][[:digit:]]*)([dmh]$)/\2 \3 \1 \2\3/' | 
awk 'BEGIN{arr["m"]=1; arr["h"]=60; arr["d"]=60*24}
     {$2=$1*arr[$2]; $1=""; print}' | 
sort -s -k1nr |
cut -d' ' -f3-
files-812888216 7d
files-1797797160 6d
files-101830442 5d
files-101830442 5d
files-1270496134 5d
files-374059185 4d
files-374059185 4d
files-909323637 4d
files-909323637 4d
files-739420408 3d
files-1986982365 2d
files-1662192679 1d
files-247106034 1d
files-550519470 19h
files-118869238 7h
files-464153317 12m
files-77614277 3m

Это должно быть значительно быстрее, чем цикл Bash. Он может быть дополнительно оптимизирован, если у вас есть gawk для замены sort и sed


Если у вас есть сортировка GNU или BSD, вы можете воспользоваться алфавитным d<h<m и не выполнять преобразование:

$ sed -E 's/([^-]*)-(.*) ([[:digit:]][[:digit:]]*)([dmh]$)/\2 \4 \3 \1-\2 \3\4/' file |
sort -s -t $' ' -k2,2 -k3,3nr -k1,1 |
cut -d $' ' -f4-
# same output
0 голосов
/ 04 ноября 2018

@ редактировать

Спасибо @shelter за помощь! Мы можем сделать это всего за:

sed 's/\(.*\) \([0-9]*\)\([a-zA-Z]*\)/\3 \2 \1 \2\3/' |
sort -k1 -k2nr |
cut -d' ' -f3-
  1. sed добавляет два новых столбца впереди, один с буквой из 3-го столбца, второй столбец с номером из 3-го столбца
  2. Затем мы сортируем, используя первый столбец и второй столбец числовой обратный
  3. Затем мы удалили дополнительные добавленные столбцы.

Я оставляю старый ответ в качестве ссылки.

Это моя идея, она работает, но определенно не самая лучшая:

sed 's/\(.*\) \([0-9]*\)\([a-zA-Z]*\)/\3 \2 \1 \2\3/' |
sort -k1 | 
{
    presuffix=''
    buff=''
    while IFS=' ' read -r suffix rest; do
        if [ "$presuffix" != "$suffix" ]; then
            echo -n "$buff" | sort -n -r -k1 
            presuffix=$suffix
            buff=''
        fi
        buff+="$rest"$'\n'
    done
    printf "%s" "$buff" | sort -n -r -k1
} |
cut -d' ' -f2-
  1. Sed get - это 1d в начале строки, поэтому к строке добавляется d 1 ... rest of the line. Таким образом, перед строкой стоят два новых столбца: один - для сортировки по алфавиту, а другой - для числовой.
  2. Затем мы сортируем, используя первый столбец (алфавит).
  3. Затем я разделяю поток на отдельные части, используя буфер, и перебираю каждую часть, используя второе поле (число) (первое поле get удалено в while read, так что теперь это первый столбец).
  4. Затем cut -d' ' -f2- убрал первый столбец (число).
  5. Это будет медленно из-за части while read, но у меня нет лучшей идеи.

@ редактировать:

Еще одно решение, действительно находящееся под влиянием комментария @shelter.

sed 's/\(.*\) \([0-9]*\)\([a-zA-Z]*\)/\3 \2 \1 \2\3/' |
while IFS=' ' read -r suffix num rest; do
    echo "$(printf "%d * 256 + (256 - %d)\n" "'$suffix" "$num" | bc)" "$rest"
done |
sort -r -n |
cut -d' ' -f2-

При условии, что в отсортированном столбце есть только суффикс одного символа (1d или 1e или 1h или 19d), а числа в отсортированном столбце меньше 256 (магическое число, может быть увеличено ), мы можем преобразовать символ в число ascii.

Затем мы можем умножить число ASCII на 256 и добавить к нему число в отсортированном столбце. Число вычитается с 256, потому что в каждом блоке мы хотим выполнить обратную сортировку с использованием чисел (сначала 7d, затем 1d). Тогда мы просто численно отсортируем это.

В качестве альтернативы мы можем использовать printf "(256 - %d) + %d", а затем перевернуть числовую сортировку, разница только в том случае, если два поля равны (например, в случае files-1662192679 и files-247106034).

Магическое число 256 должно быть больше самого большого числа в отсортированном столбце, а также больше самого большого ascii-представления символа в отсортированном столбце. Возможно, это можно расширить для обработки нескольких символов в отсортированном столбце.

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