Выберите строки из текстового файла с идентификаторами, указанными в другом файле

Я использую много сортировки grep awk в своей оболочке unix для работы с текстовыми файлами с разделителями разделов с разделителями разделов с разделителями разделов с разделителями-разделителями (размером около 10 М-100 М). В этом отношении оболочка unix является моей таблицей.

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

  • команда не найдена через скрипт оболочки, но работает на терминале
  • Возвратная перевозка не работает (Экран)
  • Сделать `rm` перемещение в корзину
  • Почему бы не использовать бесступенчатые shebangs?
  • Удалить столбец из CSV
  • Как отобразить man-страницу с groff в / на msysgit?
  • Имея файл table.csv с id\tfoo\tbar... формата id\tfoo\tbar... и ids.csv со списком идентификаторов, выберите только записи из table.csv с идентификатором, присутствующим в ids.csv .

    вид https://stackoverflow.com/questions/13732295/extract-all-lines-from-text-file-based-on-a-given-list-of-ids, но с оболочкой, а не perl.

    grep -F очевидно, создает ложные срабатывания, если ids – переменная ширина. join – это утилита, которую я никогда не мог понять. Прежде всего, для этого требуется сортировка по алфавиту (мои файлы обычно сортируются численно), но даже тогда я не могу заставить его работать, не жалуясь на неправильный порядок и пропуская некоторые записи. Поэтому мне это не нравится. grep -f против файла с ^id\t -s очень медленный, когда число идентификаторов велико. awk громоздкий.

    Есть ли хорошие решения для этого? Какие-либо конкретные инструменты для разделенных табуляцией файлов? Также будут приветствоваться дополнительные функции.

    UPD: Исправлена sort -> join

  • Bash - PS1 не обновляется с правильным именем хоста после изменения имени хоста в скрипте
  • Магический файл, перенаправляющий на стандартный вывод
  • Как сохранить переменную окружения через su -?
  • Перенаправить ввод из файла, но показывать также в stdout?
  • Результат echo $ HOSTNAME становится ключом к переменной
  • Пространства имен Shell
  • 4 Solutions collect form web for “Выберите строки из текстового файла с идентификаторами, указанными в другом файле”

    Я предполагаю, что вы имели в виду grep -f не grep -F но вам действительно нужна комбинация обоих и -w :

     grep -Fwf table.csv ids.csv 

    Причина, по которой вы получали ложные срабатывания, (я думаю, вы не объяснили), потому что если идентификатор может содержаться в другом, то оба будут напечатаны. -w устраняет эту проблему, и -F гарантирует, что ваши шаблоны рассматриваются как строки, а не регулярные выражения. От man grep :

      -F, --fixed-strings Interpret PATTERN as a list of fixed strings, separated by newlines, any of which is to be matched. (-F is specified by POSIX.) -w, --word-regexp Select only those lines containing matches that form whole words. The test is that the matching substring must either be at the beginning of the line, or preceded by a non-word constituent character. Similarly, it must be either at the end of the line or followed by a non-word constituent character. Word-constituent characters are letters, digits, and the underscore. -f FILE, --file=FILE Obtain patterns from FILE, one per line. The empty file contains zero patterns, and therefore matches nothing. (-f is specified by POSIX.) 

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

     while read pat; do grep -w "^$pat" table.csv; done < ids.csv 

    или, быстрее:

     xargs -I {} grep "^{}" table.csv < ids.csv 

    Лично я сделал бы это в perl хотя:

     perl -lane 'BEGIN{open(A,"ids.csv"); while(<A>){chomp; $k{$_}++}} print $_ if defined($k{$F[0]}); ' table.csv в perl -lane 'BEGIN{open(A,"ids.csv"); while(<A>){chomp; $k{$_}++}} print $_ if defined($k{$F[0]}); ' table.csv 

    Утилита join – это то, что вы хотите. Это требует, чтобы входные файлы были лексически отсортированы.

    Предполагая, что ваша оболочка bash или ksh:

     join -t $'\t' <(sort ids.csv) <(sort table.csv) 

    Обычное awk-решение не требует сортировки.

     awk -F '\t' 'NR==FNR {id[$1]; next} $1 in id' ids.csv table.csv 

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

    Итак, используйте опцию -t для сортировки, чтобы указать разделительный символ, и используйте параметр -k, чтобы указать поле (помня, что вам нужно поле начала и окончания – даже если это то же самое – или он будет сортировать из этого символа до конца строки).

    Итак, для файла с разделителями табуляции, как в этом вопросе, должно работать следующее (с благодарностью за ответ Гленна за структуру):

    join -t$'\t' <(sort -d ids.csv) <(sort -d -t$'\t' -k1,1 table.csv) > output.csv

    (Для справки, флаг -d означает сортировку слова. Вы также можете использовать флаг -b, чтобы игнорировать ведущие пробелы, см. man sort and man join ).

    В качестве более общего примера предположим, что вы соединяете два разделенных запятыми файлов – input1.csv на третьем столбце и input2.csv на четвертом. Вы можете использовать

    join -t, -1 3 -2 4 <(sort -d -t, -k3,3 input2.csv) <(sort -d -t, -k4,4 input2.csv) > output.csv

    Здесь параметры -1 и -2 определяют, какие поля должны объединяться в первом и втором входных файлах соответственно.

    Вы также можете использовать ruby, чтобы сделать что-то подобное:

     ruby -pe 'File.open("id.csv").each { |i| puts i if i =~ /\$\_/ }' table.csv 
    Linux и Unix - лучшая ОС в мире.