вывести строки этого первого столбца, отсутствующего в списке - PullRequest
0 голосов
/ 13 октября 2019

У меня есть список чисел в файле

cat to_delete.txt
2
3
6
9
11

и множество текстовых файлов в одной папке. В каждом файле есть строки с разделителями табуляции (может быть больше строк)первый номер не в to_delete.txt. Изменение должно заменить старый файл.

Ожидаемый вывод

7 0.33333 0.34567 0.56789 0.34543

Это то, что я получил до сих пор, который ничего не удаляет;

for file in *.txt; do awk '$1 != /2|3|6|9|11/' "$file" > "$tmp" && mv "$tmp" "$file"; done

Я просмотрел очень много подобных вопросов здесь, но все еще не могу заставить его работать. Я также попробовал grep -v -f to_delete.txt и sed -n -i '/ $ to_delete /! P'

Любая помощь приветствуется. Спасибо!

Ответы [ 2 ]

2 голосов
/ 13 октября 2019

В awk:

$ awk 'NR==FNR{a[$1];next}!($1 in a)' delete file

Вывод:

7 0.33333 0.34567 0.56789 0.34543

Объяснено:

$ awk '
NR==FNR {       # hash records in delete file to a hash
    a[$1]       
    next
}
!($1 in a)      # if $1 not found in record in files after the first, output
' delete files*   # mind the file order
0 голосов
/ 13 октября 2019

Моя первая идея заключалась в следующем:

printf "%s\n" *.txt | xargs -n1 sed -i "$(sed 's!.*!/& /d!' to_delete.txt)"
  1. printf "%s\n" *.txt - выводит файлы * .txt каждый в отдельных строках
  2. | xargs -n1 выполняет следующую команду для каждогострока, передающая содержимое строки в качестве ввода
  3. sed -i - отредактировать файл на месте
  4. $( ... ) - подстановка команды
  5. sed 's!.*!/^& /d!' to_delete.txt - для каждой строки в to_delete. txt, добавьте строку с /^ и суффикс с /d. Таким образом, из списка чисел я получаю список регулярных выражений для удаления, например:

/^2 /d
/^3 /d
/^6 /d

и так далее. Что говорит sed об удалении строк, соответствующих регулярному выражению - строка начинается с числа, за которым следует пробел.

Но я думаю, что awk будет проще. Вы можете сделать:

awk '$1 != 2 && $1 != 3 && $1 != 6 ... and so on ...`

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

awk 'FNR==NR{ map[$1] } FNR!=NR && !($1 in map)' to_delete.txt "$file"

Значение FNR==NR верно только для первого файла. Поэтому, когда мы читаем его, мы устанавливаем map[$1] (мы его «устанавливаем», именно так такой элемент существует). Тогда FNR!=NR верно для второго файла, для которого мы проверяем, является ли первый элемент ключом на карте. Если это не так, выражение является истинным, и строка выводится на печать.

все вместе:

for file in *.txt; do awk 'FNR==NR{ map[$1] } FNR!=NR && !($1 in map)' to_delete.txt "$file" > "$tmp"; mv "$tmp" "$file"; done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...