Есть ли способ использовать sed, чтобы удалить только точное совпадение строк? - PullRequest
0 голосов
/ 11 января 2019

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

foo:abc:200:1:1:1
foobar:asd:100:3:2:1
bar:test:100:2:2:2

, где первый столбец - это название книги, за которым следует имя автора, затем цена, доступное количество и проданное количество, разделенные разделителем ":"

цель здесь состоит в том, чтобы удалить книжную базу по имени и автору, в который вводит пользователь.

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

sed /"foo"/d Book.txt

Я ожидал, что результат будет

foobar:asd:100:3:2:1
bar:test:100:2:2:2

однако результат был

bar:test:100:2:2:2   

, который говорит мне, что любая строка в текстовом файле, содержащем "foo", будет удалена

Поэтому я хотел бы спросить

  1. Есть ли способ использовать sed, чтобы он удалял только точное совпадение вместо строк, содержащих foo?
  2. есть ли способ использовать разделители с sed, чтобы я мог использовать и заголовок, и автора?
  3. Должен ли я использовать что-то кроме sed?

Ответы [ 3 ]

0 голосов
/ 11 января 2019
  1. Есть ли способ использовать sed, чтобы он удалял только точное совпадение вместо строк, содержащих foo?

Да, вы можете для данного примера, если вы пометите свой шаблон поиска, чтобы он точно совпадал с foo:, вы можете удалить его. Например, если вы делаете ниже

sed '/^foo:/d' file

Шаблон ^ отмечает, что строка, начинающаяся с foo, сопровождается знаком двоеточия :, который соответствует вашему варианту использования. Предполагается, что foo может быть частью только первого столбца

  1. Есть ли способ использовать разделители с sed, чтобы я мог использовать и заголовок, и автора?
  2. Должен ли я использовать что-то кроме sed?

Если вы имеете дело с входным файлом, есть фиксированный ограничитель, например :, который никогда не станет частью вашего допустимого содержимого столбца, тогда лучше использовать awk / perl подходит для легкого чтения текста после установки ограничителя.

В качестве примера рассмотрим, например, если вы хотите изменить название количества из четвертого столбца для одной конкретной книги с именем foobar, с помощью awk вы можете просто сделать

awk -F: 'BEGIN { OFS = FS } $1 == "foobar" { $4 = 6 }1' input-file

Чтобы декодировать вышеуказанную строку, содержимое в '..' не затрагивается оболочкой и передается буквально команде, поэтому мы заключаем содержимое в одинарные кавычки. Также операторы внутри него не имеют смысла в контексте оболочки.

Таким образом, -F: устанавливает разделитель входного поля на :, то есть когда команда читает строку файла построчно, первая строка разбивается на токены, разделенные :. Первый столбец помечен $1, который расширен до $NF, что означает последний столбец строки. Деталь BEGIN { OFS = FS } назначает разделитель поля вывода тем же, что и вход, т. Е. Сохраняет ограничение :, когда awk также записывает выходные данные.

Часть $1 == "foobar" { $4 = 6 } почти не требует пояснений в том смысле, что если первый столбец содержит строку в кавычках, выполните действие внутри {..}, для которого значение четвертого столбца установлено как 6. {..}1 является сокращенной записью для {...; print}, которая предназначена для восстановления строки на основе определенных разделителей поля вывода / записи.

0 голосов
/ 11 января 2019

Это может сработать для вас (GNU sed):

sed '/\<foo\>/d' file

Или

sed '/\bfoo\b/d' file

Первое решение использует \< начальное слово и \> конечное слово. Второе решение использует границу слова \b.

P.S. Двойное число \b равно \B, поэтому для удаления строк, содержащих foobar или foobaz, но не только foo, используйте:

sed '/\bfoo\B/d' file
0 голосов
/ 11 января 2019

Используя sed лучше использовать:

sed -E '/(^|:)foo(:|$)/d' file

foobar:asd:100:3:2:1
bar:test:100:2:2:2

, который гарантирует, что foo предшествует начало или : и затем конец или :.

Однако это задание больше подходит для awk, поскольку данные разделяются двоеточием:

awk -F: '$1 != "foo"' file
...