Сортировать файл по полю, начинающемуся со строки

Сортировать файл по полю, начинающемуся со строки

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

/home/zz/AUTHORBOOKS/Author-Chomsky-Who-Rules-the-World.epub
/home/zz/AUTHORBOOKS/Author-Cioran-Il-nulla.epub
/home/zz/BOOKS/Author-Artemis-Mathematica-Examples.nb
/home/zz/Books/Author-Zigniwe-Hisory-Medicine.pdf
/home/z1/OLDBOOKS1/OLDBOOKS2/Author-Watanabe-Waterloo.pdf
/home/z2/OLDBOOKS1/OLDBOOKS2/Author-Barbero-Lepanto.epub.pdf

Мне бы хотелось, чтобы файл был отсортирован следующим образом:

/home/zz/BOOKS/Author-Artemis-Mathematica-Examples.nb
/home/z2/OLDBOOKS1/OLDBOOKS2/Author-Barbero-Lepanto.epub.pdf
/home/zz/AUTHORBOOKS/Author-Chomsky-Who-Rules-the-World.epub
/home/zz/AUTHORBOOKS/Author-Cioran-Il-nulla.epub
/home/z1/OLDBOOKS1/OLDBOOKS2/Author-Watanabe-Waterloo.pdf
/home/zz/Books/Author-Zigniwe-History-Medicine.pdf

То есть, по алфавиту, согласно строкеAuthor-...

Как видите, положение Author-...не является постоянным.

Как я могу это сделать?

решение1

Попробуйте следующую bashкоманду:

sort -t- -d -k2 -o output.txt input.txt

Он имеет четыре опции плюс имя входного файла input.txt. Если этот файл отсутствует в текущем каталоге, вам придется указать path/to/the/folder/input.txt. Опции и их аргументы следующие:

  • -t обозначает разделитель полей. Мы используем -в качестве разделителя, так что все до и после -считается отдельными столбцами.
  • -d указывает на сортировку по словарю. Например, Apple стоит перед Berry.
  • -k2 указывает столбец, по которому нужно сортировать, в данном случае второй столбец. Обратите внимание, что первый столбец — это все, что находится перед первым -. Например, /home/zz/BOOKS/Author. Второй столбец находится между первым и вторым -, то есть Artemis.
  • -o output.txtперенаправляет отсортированный вывод в файл, а не на терминал.

Надеюсь это поможет

решение2

Хотя для данного примера это излишне из-зарешение, предложенное в ответе пользователя 68186, в более общем случае в GNU awk можно сделать что-то вроде этого:

gawk -F/ '
  function mycmp(i1,v1,i2,v2) {
    m = split(v1,a);
    n = split(v2,b);
    return a[m]"" > b[n]"" ? 1 : a[m]"" < b[n]"" ? -1 : 0
  }
  {
    lines[NR] = $0
  }
  END {
    PROCINFO["sorted_in"] = "mycmp";
    for(i in lines) print lines[i]
  }
' file

Обратите внимание, что сортировка выполняется в соответствии с лексическим значением всего, что находится после последнего /, поэтому, если формат такой, Author-<author name>-<title>.<extension>то это будет

  • фиксированная строка Author-(которая не имеет никакого эффекта, так как имеет одинаковый вес для всех строк); затем
  • <author name>-; затем
  • <title>.; затем
  • <extension>

Это похоже на то, как работает sortпростой KEYDEF в GNU -t- -k2, т.е. эффективный ключ сортировки начинается с <author name>и продолжается до конца строки.

Явный разделитель опущен в splitвызовах, так что они наследуют значение FS, что позволяет легко изменить его для систем, использующих другой разделитель пути. Добавленные пустые строки ""в mycmpфункцию вызывают лексическое сравнение, даже если имена файлов числовые — см., напримерКак awk преобразует строки в числа и наоборот


Если вы предпочитаете использовать эту sortкоманду, вы можете воспользоваться возможностями GNU awkДвусторонняя связь с другим процессомк:

  • дублировать последнее /поле, разделенное -, в начале строки
  • передать результат sortкоманде
  • перечитайте отсортированный результат, удалите дублирующийся префикс и распечатайте

то есть

gawk -F/ '
  BEGIN {OFS=FS; cmd = "sort -d"} 
  {print $NF $0 |& cmd} 
  END {
    close(cmd,"to"); 
    while(cmd |& getline){$1 = ""; print};
    close(cmd,"from")
  }
' file

Здесь есть небольшой обман, поскольку абсолютные пути (строки начинаются с /) подразумевают изначально пустое поле; для обработки относительных путей вам нужно будет изменить print $NF $0на print $NF,$0, чтобы вставить «отсутствующий» разделитель, а затем, возможно, использовать регулярное выражение sub()вместо более простого $1 = ""способа удаления начального элемента.

Помимо того, что это решение потенциально быстрее и эффективнее в плане использования памяти , оно также позволяет напрямую добавлять gawkдругие опции, например .sortcmd = "sort -d -t " FS " -k1,1r"

Связанный контент