Поиск строки и удаление всего содержимого между двумя разделителями

Ваш файл не содержит кавычек, это новое поведение вывода ls.

См.:Почему 'ls' внезапно заключает элементы с пробелами в одинарные кавычки?


Вы можете использовать

cp "A long file n"* short_filename

*должен быть вне кавычек

или экранируйте все пробелы (и другие специальные символы, такие как \, ;или |и т. д.)

cp A\ long\ file\ n* short_filename

0
08.02.2021, 16:56
4 ответа

Как было отмечено, jq— это инструмент, который можно использовать для этого типа данных. Однако jq накладывает определенные синтаксические ограничения, такие как «списки объектов должны быть в массиве, обозначенном квадратными скобками».

Если вы не можете убедиться, что файл уже действителен json, вы можете использовать sed для его предварительной обработки (и мы выполним первоначальный запуск через jq, потому что результат проще для глаз, а также проверяют на правильность.)

$ sed 's/^/[/; s/,$/]/' data.txt | jq -r '.[]'
{
  "something": false,
  "more": "123",
  "moresamerecord": "otherstuff"
}
{
  "something": false,
  "more": "abc",
  "moresamerecord": "otherstuff"
}
{
  "something2": false,
  "more": "def",
  "moresamerecord": "otherstuff"
}
{
  "something2": false,
  "more": "456",
  "moresamerecord": "otherstuff"
}

Теперь давайте изменим команду jq, чтобы удалить все совпадающие объекты"more": "abc":

$ sed 's/^/[/; s/,$/]/' data.txt | jq -r '.[] | select(.more != "abc")'
{
  "something": false,
  "more": "123",
  "moresamerecord": "otherstuff"
}
{
  "something2": false,
  "more": "def",
  "moresamerecord": "otherstuff"
}
{
  "something2": false,
  "more": "456",
  "moresamerecord": "otherstuff"
}

Наконец, кажется, что вы также хотите, чтобы шаг постобработки -сжимал его обратно в одну строку с разделителями-запятыми -и без пробелов:

$ sed 's/^/[/; s/,$/]/' data.txt | jq -r '.[] | select(.more != "abc")' | sed 's/}$/},/' | tr -d ' \n'
{"something":false,"more":"123","moresamerecord":"otherstuff"},{"something2":false,"more":"def","moresamerecord":"otherstuff"},{"something2":false,"more":"456","moresamerecord":"otherstuff"},
1
18.03.2021, 22:31

Основная идея состоит в том, чтобы расширить шаблон до разделителей, а не дальше.

Таким образом, чтобы найти соответствие от ближайшего {к "abc", вы можете искать {, за которым следуют любые символы, которые не являются {. Точно так же вы можете расшириться от "abc"до ближайшего следующего }, ища символы, которые не являются }, за которыми следует `}'.

Затем есть несколько пограничных случаев для обработки запятых.

sed 's/{[^{]*"abc"[^}]*}//;s/,,/,;s/,$//;s/^,//'

Если ваши данные более сложны, чем вы показываете, и, в частности, если {и }могут вкладываться друг в друга, вы, вероятно, захотите переключиться на синтаксический анализ. Регулярные выражения «не могут считаться», поэтому, хотя вы можете писать шаблоны, которые обрабатывают любую конкретную конечную глубину (, например. 3 )вы не можете работать с произвольной глубиной.

Совет в комментариях по использованию jq, безусловно, стоит попробовать, а не использовать sed.

0
18.03.2021, 22:31

Если jqне является решением, я предлагаю это:

# Instead of a single line pattern matching,
# make the "records" one per line
# then delete the line with the pattern
# finally get everything again to a single line
sed -e 's:,{:\n{:g;s:,$::' file | sed '/abc/d' | tr '\n' ','

Шаг за шагом:

$ sed -e 's:,{:\n{:g;s:,$::' file
{"something":false,"more":"123","moresamerecord":"otherstuff"}
{"something":false,"more":"abc","moresamerecord":"otherstuff"}
{"something2":false,"more":"def","moresamerecord":"otherstuff"}
{"something2":false,"more":"456","moresamerecord":"otherstuff"}
$ sed -e 's:,{:\n{:g;s:,$::' foo.txt | sed '/abc/d'
{"something":false,"more":"123","moresamerecord":"otherstuff"}
{"something2":false,"more":"def","moresamerecord":"otherstuff"}
{"something2":false,"more":"456","moresamerecord":"otherstuff"}
$ sed -e 's:,{:\n{:g;s:,$::' foo.txt | sed '/abc/d' | tr '\n' ','
{"something":false,"more":"123","moresamerecord":"otherstuff"},{"something2":false,"more":"def","moresamerecord":"otherstuff"},{"something2":false,"more":"456","moresamerecord":"otherstuff"},
0
18.03.2021, 22:31
awk '
  BEGIN { FS = "},{" }
  { k=0
    for (i=1; i<=NF; i++)
      if ($i !~ /"abc"/)
        printf "%s%s", (k++?FS:""), $i
    $0=""
  }1
' file

$ cat file \
| sed -e 's/},{/}\n{/g'           \
| sed -E '/([{:,])"abc"([,:}])/d' \
| paste -sd, -                    \
;
  • Разделить записи на одну / строку.
  • Теперь удалите все записи, содержащие"abc"
  • Прошить записи запятой,

Выход:

{"something":false,"more":"123","moresamerecord":"otherstuff"},{"something2":false,"more":"def","moresamerecord":"otherstuff"},{"something2":false,"more":"456","moresamerecord":"otherstuff"}
0
18.03.2021, 22:31

Теги

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