Быстрый способ удалить номер только один раз из списка номеров в Bash - PullRequest
0 голосов
/ 21 февраля 2019

У меня есть файл, который представляет собой список чисел.

list_of_numbers

40426
140
26
3502
140
899320

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

numbersrs_to_remove

140
3502

, поэтому выходной файл должен быть

40426
26
140
899320

Удалять только один раз, чтобы осталось 140, как показано дважды в list_of_numbers.

В настоящее время я делаю

while read line ; do

    sed -i "0,/^$line$/s///" list_of_numbers

done < numbers_to_remove

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

Ответы [ 3 ]

0 голосов
/ 22 февраля 2019

Сначала сохраните все числа для удаления в массиве.
После обработки первого файла (FNR==NR) перейдите ко второму файлу.
Если в массиве для удаления найдено значение, удалите его из массива.и посмотрите на следующую строку.
Если значение отсутствует в массиве, выведите его.

awk 'FNR==NR{a[$0];next}
     $0 in a{delete a[$0];next}
     {print}' numbers_to_remove list_of_numbers
0 голосов
/ 22 февраля 2019

С awk - Ожидаются предварительно отсортированные записи.Порядок не имеет значения, если оба файла используют одну и ту же схему упорядочения.

awk '
  BEGIN{ getline skipnum < "numbers_to_remove"; old=""; }
  { if ( $0 == skipnum && old != skipnum ) {
       old = skipnum;
       getline skipnum < "a";
       next;
    } else print;
  }
' list_of_numbers

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

Это быстрое однократное чтение каждого файла.

Если вы не хотите предварительно сортировать их, используйте ассоциативный массив и удалите каждый элемент как найденный.

awk '
  BEGIN {
    while (getline skipnum < "numbers_to_remove") { skips[skipnum] = 1; }
  }
  { if ( $0 in skips ) {
       delete skips[$0];
       next;
    } else print;
  }
' list_of_numbers
0 голосов
/ 21 февраля 2019

One sed должно быть быстрее их много:

list_of_numbers=(
    40426 140 26
    3502 140 899320
)

numbers_to_remove=(
    140 3502
)

printf "%s\n" "${list_of_numbers[@]}" |
sed "$(printf '0,/^%d$/s///\n' "${numbers_to_remove[@]}")/^$/d"

выведет:

40426
26
140
899320
  • printf повторяет строку формата для аргументов.Таким образом, printf "A %d" 1 2 выведет A 1A 2.
  • . Сначала мы выводим список чисел на отдельных символах новой строки
  • , затем форматируем аргумент sed, чтобы он был 0,/^<number here>$/s///<newline> для каждого числа в списке.номера для удаления.Новая строка используется для разделения команд sed.
  • Последняя команда sed предназначена для удаления пустых строк, т.е./^$/d - удалить строки, в которых ничего нет.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...