Например, у меня есть файл со следующим содержимым:
eggs
bacon
cereal
eggs
bacon
cheese
cereal
Выход:
eggs
bacon
cereal
В этом примере я хочу удалить строки между словами eggs
и cereal
, но только если cheese
между ними есть .
Как я могу это сделать, используя sed
?
Меня попросили быть более конкретным, поэтому вот что я хочу сделать, и я надеюсь, что это прояснит ситуацию:
WeaponData
{
TextureData
{
"crosshair"
{
"file" "vgui/replay/thumbnails/"
"x" "0"
"y" "0"
"width" "64"
"height" "64"
}
"weapon"
{
"file" "sprites/bucket_bat_red"
"x" "0"
"y" "0"
"width" "200"
"height" "128"
}
"weapon_s"
{
"file" "sprites/bucket_bat_blue"
"x" "0"
"y" "0"
"width" "200"
"height" "128"
}
"ammo"
{
"file" "sprites/a_icons1"
"x" "55"
"height" "15"
}
"crosshair"
{
"file" "sprites/crosshairs" <---
"x" "32"
"y" "32"
"width" "32"
"height" "32"
}
"autoaim"
{
"file" "sprites/crosshairs"
"x" "0"
"y" "48"
"width" "24"
"height" "24"
}
}
}
Вот команда, которую я попробовал:
sed '/"crosshair"/,/}/d' file.txt
Эта команда просто удаляет все от самого первого "crosshair"
до самого последнего }
, независимо от того, есть ли между ними строка "sprites/crosshairs"
или нет.
Я хочу удалить только от "crosshair"
до }
, если между шаблонами "sprites/crosshairs"
найдена строка. Однако в текстовом файле есть и другие блоки кода, содержащие "sprites/crosshairs"
.
Такой как:
"autoaim"
{
"file" "sprites/crosshairs"
"x" "0"
"y" "48"
"width" "24"
"height" "24"
}
Это не может быть удалено. Я ГЛУБОКО извиняюсь за то, что не объяснил это раньше, но я не думал, что это будет необходимо.
Предложение don_crissti работает довольно хорошо, этоsed '/crosshair/,/\}/{H;/\}/!d;s/.*//;x;/sprites\/crosshairs/d;s/.//;}' infile
Однако вывод таков:
... "autoaim" { } }
"autoaim"
частично удален, но не полностью, но как вы видите, блок, содержащий его, "sprites/crosshairs"
удален, как я и хотел сделать, но autoaim
все еще не может быть изменен
решение1
sed '/^[[:blank:]]*"crosshair"/,/}/{H;/}/!d;s/.*//;x;/sprites\/crosshairs/d;s/.//;}' infile
Как это работает:
sed '/^[[:blank:]]*"crosshair"/,/}/{ # in this range
H # append each line to hold buffer
/}/!d # delete it if not the end of range
s/.*// # empty the pattern space
x # exchanges buffers
/sprites\/crosshairs/d # delete pattern space if it matches
s/.// # remove leading newline, autoprint
}' infile
Это предполагает, что за совпадающими строками ^[[:blank:]]*"crosshair"
всегда следует блок строк, заключенный в фигурные скобки, как в вашем примере.
решение2
если perl
все в порядке, можно использовать режим абзаца ( -00
опция) и использовать многострочное сопоставление регулярных выражений
$ cat ip.txt
eggs
bacon
cereal
eggs
bacon
cheese
cereal
$ perl -00 -ne 'print if !/^eggs.*cheese.*cereal$/ms' ip.txt
eggs
bacon
cereal