Для иллюстрирования его далее, у нас есть два содержания файла:
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
то, что я хочу, должно выполнить итерации первого столбца file1 и удалить записи, которые соответствуют в file2 и производят вывод как:
This
is
my
word
file
Как я могу продолжить двигаться?
Вы хотите использовать awk, чтобы считать file1 и помнить все его слова. Затем считайте file2 и произведите любые слова, которые не были замечены от file1:
gawk -v RS='[[:space:]]+' 'NR==FNR {words[$1]=1; next} !($1 in words)' file1 file2
, Который использует любую последовательность пробела как разделитель записей, таким образом, каждое слово рассматривают как отдельную "строку". Это теперь GNU awk конкретный, но это - значение по умолчанию awk на Ubuntu
Можно использовать grep -f FILE
для получения шаблонов из файла FILE
. В Вашем случае я рекомендую некоторые дополнительные флаги (см. объяснение ниже) для следующего финала grep
вызов:
grep -v -x -F -f file1 -- file2
-f FILE
†“Получают шаблоны от FILE
, один на строку.
-F
†“Интерпретируют шаблон как список фиксированных строк, разделенных новыми строками, любая из которых должна быть подобрана.
-x
†“Выбирают только те соответствия, которые точно соответствуют целой строке. (Можно хотеть удалить эту опцию, если Вы хотите позволить частично согласующие отрезки длинной линии.)
-v
†“Инвертируют смысл соответствия, для выбора несогласующих отрезков длинной линии.
<глоток> Источник: GNU grep документация или альтернативно страница руководства глоток>
Все опции, используемые выше, указаны POSIX и не требуют расширений GNU.
Используйте grep с -v
(инвертирование) флаг.
С использованием расширенного regex (-E
), можно сделать |
- разделенный список шаблонов, которые Вы хотите исключить, например, pattern1|pattern2|pattern3
:
grep -v -E "^[0-9]|world|hello" file
Хотя критерии удаления не очень ясны, я предполагаю, что части для удаления (www\n1_www\n2_www
) для всего Word www
(исправьте меня, если я неправ)
Используя (гну) sed:
sed -zr 's/(\w+)\n1_\1\n2_\1\n//g' ex
Эта командная строка должна добиться цели:
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
не применимо к этому сценарию, потому что конечный файл будет много раз перезаписываться, таким образом, необходимо будет создать резервную копию заранее.