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

Чтобы проиллюстрировать это, у нас есть два файла:

file1

hello 1_hello 2_hello world 1_world 2_world hello1 1_hello1 2_hello1 world1 1_world1 2_world1

file2

This hello 1_hello 2_hello is world 1_world 2_world my hello1 1_hello1 2_hello1 word world1 1_world1 2_world1 file

что Я хочу, чтобы итерация первого столбца файла1 и удаление записей, которые соответствуют в файле2, и выводятся как:

This is my word file

Как я могу продолжить?

0
задан 20 September 2017 в 19:08

10 ответов

Вы можете использовать grep -f FILE для получения паттернов из файла FILE. В вашем случае я рекомендую несколько дополнительных флагов (см. Объяснение ниже) для следующего окончательного вызова grep:

grep -v -x -F -f file1 -- file2 -f FILE - Получить шаблоны из FILE, по одному на строку. -F. Интерпретировать шаблон как список фиксированных строк, разделенных символами новой строки, любой из которых должен быть сопоставлен. -x - выберите только те совпадения, которые точно соответствуют всей строке. (Вы можете удалить эту опцию, если хотите разрешить частично совпадающие строки.) [F9] - инвертировать смысл соответствия, чтобы выбрать несогласованные строки.

Источник: документация GNU grep или, альтернативно, ее страница руководства

Все параметры, используемые выше, задаются POSIX и не требуют расширений GNU.

3
ответ дан 18 July 2018 в 06:31

Вы хотите использовать awk для чтения файла1 и запомнить все его слова. Затем прочитайте файл2 и выведите любые слова, которые не были видны из файла1:

gawk -v RS='[[:space:]]+' 'NR==FNR {words[$1]=1; next} !($1 in words)' file1 file2

Использует любую последовательность пробелов в качестве разделителя записей, поэтому каждое слово рассматривается как отдельная «строка». Это теперь GNU awk, но это awk по умолчанию на Ubuntu

5
ответ дан 18 July 2018 в 06:31

Хотя критерии удаления не очень ясны, я предполагаю, что части для удаления являются (www\n1_www\n2_www) для всего слова www (исправьте меня, если я ошибаюсь)

Использование (gnu) sed:

sed -zr 's/(\w+)\n1_\1\n2_\1\n//g' ex
0
ответ дан 18 July 2018 в 06:31

Эта командная строка должна выполнить трюк:

while read -r word; do sed -e "s/\<$word\>//g" -e '/^\s*$/d' file2 -i; done < file1

После выполнения вышеуказанной команды выходной файл - file2 - должен выглядеть так:

This is my word file

Более читаемая версия приведенной выше командной строки:

while read -r word; do \ sed -e "s/\<$word\>//g" -e '/^\s*$/d' file2 -i; \ done < file1

Цикл while читает строку строки за строкой - < file1. Значение каждой строки используется как значение временной созданной переменной, называемой $word - -r word. Эта переменная используется как аргумент внутри команды sed, и она заменяется [s] пустым значением в file2, первым выражением: "s/\<$word\>//g" = s/<source_value>/<replacement_value>/g. Флаг g означает - применить замену ко всем совпадениям. Затем, если в файле есть пустая строка, она удаляется - второе выражение: '/^\s*$/d'.

Нам нужно использовать синтаксис \<...\>, чтобы найти только точные совпадения. Нам нужны двойные кавычки - "..." - для первого выражения, потому что $word - это имя переменной, и мы хотим расширить его как свое значение в команде sed.

Опция -i означает, что изменения будут сделаны в их местах в целевом файле - file2. Если эта опция будет удалена, результат будет передан в stdout, но это не будет иметь смысла. Опция -i.bak неприменима к этому сценарию, потому что целевой файл будет перезаписан много раз, поэтому вы должны создать резервную копию заранее.

1
ответ дан 18 July 2018 в 06:31

Используйте grep с флагом -v (инвертировать).

С помощью расширенного регулярного выражения (-E) вы можете сделать | -сегментированный список шаблонов, которые вы хотите исключить, например pattern1|pattern2|pattern3:

grep -v -E "^[0-9]|world|hello" file
0
ответ дан 18 July 2018 в 06:31

Вы можете использовать grep -f FILE для получения паттернов из файла FILE. В вашем случае я рекомендую несколько дополнительных флагов (см. Объяснение ниже) для следующего окончательного вызова grep:

grep -v -x -F -f file1 -- file2 -f FILE - Получить шаблоны из FILE, по одному на строку. -F. Интерпретировать шаблон как список фиксированных строк, разделенных символами новой строки, любой из которых должен быть сопоставлен. -x - выберите только те совпадения, которые точно соответствуют всей строке. (Вы можете удалить эту опцию, если хотите разрешить частично совпадающие строки.) [F9] - инвертировать смысл соответствия, чтобы выбрать несогласованные строки.

Источник: документация GNU grep или, альтернативно, ее страница руководства

Все параметры, используемые выше, задаются POSIX и не требуют расширений GNU.

3
ответ дан 24 July 2018 в 18:37

Вы хотите использовать awk для чтения файла1 и запомнить все его слова. Затем прочитайте файл2 и выведите любые слова, которые не были видны из файла1:

gawk -v RS='[[:space:]]+' 'NR==FNR {words[$1]=1; next} !($1 in words)' file1 file2

Использует любую последовательность пробелов в качестве разделителя записей, поэтому каждое слово рассматривается как отдельная «строка». Это теперь GNU awk, но это awk по умолчанию на Ubuntu

5
ответ дан 24 July 2018 в 18:37
  • 1
    Это просто потрясающе, спасибо за то, что поделились этими знаниями! – dessert 20 September 2017 в 21:05
  • 2
    @dessert: Если вы хотите получить еще более элегантный ответ, см. мой. ;-П – David Foerster 2 October 2017 в 13:19

Хотя критерии удаления не очень ясны, я предполагаю, что части для удаления являются (www\n1_www\n2_www) для всего слова www (исправьте меня, если я ошибаюсь)

Использование (gnu) sed:

sed -zr 's/(\w+)\n1_\1\n2_\1\n//g' ex
0
ответ дан 24 July 2018 в 18:37

Эта командная строка должна выполнить трюк:

while read -r word; do sed -e "s/\<$word\>//g" -e '/^\s*$/d' file2 -i; done < file1

После выполнения вышеуказанной команды выходной файл - file2 - должен выглядеть так:

This is my word file

Более читаемая версия приведенной выше командной строки:

while read -r word; do \ sed -e "s/\<$word\>//g" -e '/^\s*$/d' file2 -i; \ done < file1

Цикл while читает строку строки за строкой - < file1. Значение каждой строки используется как значение временной созданной переменной, называемой $word - -r word. Эта переменная используется как аргумент внутри команды sed, и она заменяется [s] пустым значением в file2, первым выражением: "s/\<$word\>//g" = s/<source_value>/<replacement_value>/g. Флаг g означает - применить замену ко всем совпадениям. Затем, если в файле есть пустая строка, она удаляется - второе выражение: '/^\s*$/d'.

Нам нужно использовать синтаксис \<...\>, чтобы найти только точные совпадения. Нам нужны двойные кавычки - "..." - для первого выражения, потому что $word - это имя переменной, и мы хотим расширить его как свое значение в команде sed.

Опция -i означает, что изменения будут сделаны в их местах в целевом файле - file2. Если эта опция будет удалена, результат будет передан в stdout, но это не будет иметь смысла. Опция -i.bak неприменима к этому сценарию, потому что целевой файл будет перезаписан много раз, поэтому вы должны создать резервную копию заранее.

1
ответ дан 24 July 2018 в 18:37

Используйте grep с флагом -v (инвертировать).

С помощью расширенного регулярного выражения (-E) вы можете сделать | -сегментированный список шаблонов, которые вы хотите исключить, например pattern1|pattern2|pattern3:

grep -v -E "^[0-9]|world|hello" file
0
ответ дан 24 July 2018 в 18:37

Другие вопросы по тегам:

Похожие вопросы: