我有一个如下文件:
city-italy
good food
bad climate
-
city-india
bad food
normal climate
-
city-brussel
normal dressing
stylish cookings
good food
-
问题 - 我想grep city
和food
,因为“食物”是“坏”。
例如 - 对于上面的问题,我需要一个grep命令来得到如下的答案
city-india
bad food
请帮助我,如果两者并行成功,我将如何获得模式1和模式2。
我的意思是两个模式应该匹配,它应该在下一行中grep。
答案 0 :(得分:6)
您可以使用管道执行此操作 - grep -A1 city <filename> | grep -B1 "bad food"
或cat filename | grep -A1 city | grep -B1 "bad food"
(或管道的任何其他流源)
答案 1 :(得分:1)
如果保证城市名称在食品质量之前(允许其间的任何其他信息):
sed -n -e '/^city/h' -e '/bad food/{x;G;p}' input
将每个城市的名称保留在保留缓冲区中,并在匹配不良食物时打印最后一个城市名称。
答案 2 :(得分:0)
使用bad food
(由于RS)
gnu awk
城市
awk '/bad food/ {print RS $1}' RS="city" file
city-india
答案 3 :(得分:0)
另一个awk系列:
kent$ awk 'BEGIN{FS=OFS="\n";RS="-"FS}/bad food/{print $1,$2}' file
city-india
bad food
答案 4 :(得分:0)
如果确保订单,您可以直接使用命令grep
和OR:
grep -e "city" -e "food" FILE_INPUT
然后希望这个城市将遵循其食物特征。
结果如下:
city-italy
good food
city-india
bad food
city-brussel
good food
您可以更改模式以获得更多过滤结果。
答案 5 :(得分:0)
I know this is an old question, but here's a "robust" alternative (cuz I'm into that):
grep -x -e'city-.*' -e'good food' -e'bad food' -e'-' | tr \\n \| | sed -e's/|-|/\n/g' | grep -xe'[^|]\+|[^|]\+' | grep -e'|bad food$' | tr \| \\n
grep -x -e'city-.*' -e'good food' -e'bad food' -e'-'
: only keep the lines that contain a "city line", a "food line" (either good or bad), or a "separator line" (the food line expression could be better, I know), the -x
argument to grep
will make it return a line only if the whole line matches the given expression (incidentally, this first stage makes the whole pipe not choke on differently-sized "registers"),
tr \\n \|
: turn newlines into pipes (you can use any character that does not appear in the original file, pipe works, so does a colon, you get the idea),
sed -e's/|-|/\n/g'
: replace the |-|
string by a newline (this are the places we know a "register" ends, since we only kept the datums we're interested in and the separators, we know that now we have each of our "registers" in a single line, with their fields separated by pipes),
grep -xe'[^|]\+|[^|]\+'
: only keep lines containing exactly two fields (ie. the city and food fields),
grep -e'|bad food$'
: keep only lines ending in |bad food
,
tr \| \\n
: turn pipes back into newlines (nb. this is just here so that the output conforms to the question's specification, it's not really needed, nor preferred in my opinion).
After grep -x -e'city-.*' -e'good food' -e'bad food' -e'-'
:
city-italy
good food
-
city-india
bad food
-
city-brussel
good food
-
After tr \\n \|
:
city-italy|good food|-|city-india|bad food|-|city-brussel|good food|-|
After sed -e's/|-|/\n/g'
:
city-italy|good food
city-india|bad food
city-brussel|good food
After grep -xe'[^|]\+|[^|]\+'
: idem, since we don't have a "city line" without a "food line" in the example given, nor a register containing two "city lines" and a "food line", nor a register containing a "city line" and two "food lines", nor... you get the picture,
After grep -e'|bad food$'
:
city-india|bad food
After tr \| \\n
:
city-india
bad food
The input file basically consists of different "registers", each containing a variable number of "fields", but instead of having them in an "horizontal" format, we find them in a "vertical" one, ie. one field per line with a lone -
separating whole registers.
The pipe above supports any amount of fields in each register, it only assumes that:
Registers are separated by a lone -
,
The "city fields" are all of the form city-*
,
The "food fields" are either good food
or bad food
,
If at all existent, "city" fields appear before "food" fields.
(this last one I find particularly hard to relax, at least in a "normal"-ish pipe like the one given).
I does not assume that:
Each register has a "city" and a "food" field,
Each register has only "city" and "food" fields.
I'm not claiming this is in any way better than any of the other answers, it's just that I can't do sed
or awk
to save my own life, and often find pipes like this are helpful in understanding how the file gets filtered and transformed.
All in all, it's just a matter of taste.