2

Существует ли инструмент (или опция для sort), который будет переупорядочивать строки файла так, чтобы они упорядочивались как ключи в другом файле?

Например, у меня есть файл данных:

T01F01475558    30
T01F022B3A17    31
T01F022EEDFD    19
T01F026E0209    19

И еще один (сортировка "ключевого" файла):

T01F022EEDFD
T01F026E0209
T01F022B3A17
T01F01475558

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

Есть ли инструмент UNIX, о котором я не знаю, который сделает это?

1 ответ1

0

Каждый ключ уникален (без дубликатов), и в каждом файле одинаковое количество строк.

Это предположение очень важно. Если это так, то эта команда выполнит эту работу (в Bash):

paste <(nl key.file | sort -k 2 | cut -f 1) <(sort data.file) | sort -n | cut -f 2-

Немногие инструменты используют символы табуляции в качестве разделителей. По этой причине вкладки не должны появляться в key.file ( хотя они могут появляться и в data.file ). В любом случае вменяемые записи в key.file должны формировать один столбец, поэтому это не должно быть проблемой.

Объяснение:

  1. nl добавляет номер строки перед каждой строкой key.file ; это заставляет сами ключи перемещаться во второй столбец; sort -k 2 сортирует по второму столбцу, т.е. по ключам. Затем ключи отбрасываются с помощью команды cut -f 1 .
  2. Другой sort сортирует data.file . Поскольку передние ключи уникальны, эта сортировка по умолчанию эквивалентна сортировке по отдельным ключам.
  3. Два результата из sort объединяются с помощью paste . Без первого cut пример строки будет:

         4  T01F01475558    T01F01475558    30
    

    Уникальность ключей и равное их количество в обоих файлах имеют решающее значение. В результате одни и те же ключи от обоих sort -s встречаются в одной и той же линии , оставляя paste Поскольку вам не нужны дублирующиеся ключи, чтобы занять память, первый cut был использован как можно скорее. С этим реальным примером строки оставляя paste является довольно:

         4  T01F01475558    30
    
  4. Эти строки затем сортируются в соответствии с их числовым значением. Номера строк от nl находятся впереди, поэтому эта операция вводит желаемый порядок.

  5. В конце cut отбрасывает первый столбец, оставляя точные строки из data.file , но в желаемом порядке.

В качестве альтернативы вы можете попробовать это (проверено в Bash):

while IFS='' read -r ; do
   [ -n "$REPLY" ] && grep "^$REPLY " data.file
done <key.file

Обратите внимание, что код ожидает пробел после каждого ключа в data.file .

Плюсы:

  • key.file может указывать любое количество ключей, дубликатов ключей, несуществующих ключей. В этом случае не думайте "сортировка", думайте "извлечение нужных строк одна за другой".
  • Вы можете транслировать ввод (например, stdin вместо key.file , просто пропустите <key.file) и получить результат на лету.

Минусы:

  • grep будет интерпретировать ключи как регулярные выражения, это может иметь неприятные последствия. Есть grep -F но в общем случае вам нужно ^ в шаблоне.
  • read медленное; порождает grep снова и снова медленно; Открытие data.file снова и снова происходит медленно.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .