Bash:在角色之间捕捉一个文件

And*_*ata 1 bash awk grep sed cat

我已经尝试了各种解决方案来找到一个很好的方法来通过一个以特定单词开头的文件,并以特定的单词结束.

假设我有一个名为的文件states.txt包含:

Alabama
Alaska
Arizona
Arkansas
California
Colorado
Connecticut
Delaware
Florida
Georgia
Hawaii
Idaho
Illinois 
Indiana
Iowa
Kansas
Kentucky
Louisiana
Maine
Maryland
Massachusetts
Michigan
Minnesota
Mississippi
Missouri
Montana 
Nebraska
Nevada
New Hampshire
New Jersey
New Mexico
New York
North Carolina
North Dakota
Ohio
Oklahoma
Oregon
Pennsylvania 
Rhode Island
South Carolina
South Dakota
Tennessee
Texas
Utah
Vermont
Virginia
Washington
West Virginia
Wisconsin
Wyoming
Run Code Online (Sandbox Code Playgroud)

我想cat states.txt并获得以下开头Idaho和结束的状态South Dakota.

我也想忽略这样一个事实,即状态是按字母顺序排列的(我要的实际文件内容不按此顺序排列).

结果应如下所示:

Idaho
Illinois 
Indiana
Iowa
Kansas
Kentucky
Louisiana
Maine
Maryland
Massachusetts
Michigan
Minnesota
Mississippi
Missouri
Montana 
Nebraska
Nevada
New Hampshire
New Jersey
New Mexico
New York
North Carolina
North Dakota
Ohio
Oklahoma
Oregon
Pennsylvania 
Rhode Island
South Carolina
South Dakota
Run Code Online (Sandbox Code Playgroud)

感谢您抽出宝贵的时间和耐心.我感谢任何提供的帮助.

Win*_*ute 7

使用带有模式范围的sed:

sed '/^Idaho$/,/^South Dakota$/!d' filename
Run Code Online (Sandbox Code Playgroud)

或者具有相同模式范围的awk:

awk '/^Idaho$/,/^South Dakota$/' filename
Run Code Online (Sandbox Code Playgroud)

在两种情况下,^$相匹配的开始和线路,分别的端部,所以^Virginia$只匹配,如果整个线是Virginia(即,West Virginia不匹配).

或者,如果您更喜欢固定字符串匹配而不是正则表达式匹配(这在这里没有区别,但可能在其他情况下):

awk '$0 == "Idaho", $0 == "South Dakota"' filename
Run Code Online (Sandbox Code Playgroud)


Ed *_*ton 7

awk '/Idaho/{f=1} f; /South Dakota/{f=0}' file
Run Code Online (Sandbox Code Playgroud)

请参阅解释awk命令以获取更多awk范围的习语.

不要养成使用习惯,/start/,/end/因为它使得琐碎的事情变得非常简单,但需要完全重写或复制条件,即使最轻微的要求改变(例如不打印边界线).

例如,给定此输入文件:

$ cat file
a
b
c
d
e
Run Code Online (Sandbox Code Playgroud)

打印b和d之间的行,然后排除其中一条或两条边界线:

$ awk '/b/{f=1} f; /d/{f=0}' file
b
c
d

$ awk 'f; /b/{f=1} /d/{f=0}' file
c
d

$ awk '/b/{f=1} /d/{f=0} f;' file
b
c

$ awk '/d/{f=0} f; /b/{f=1}' file
c
Run Code Online (Sandbox Code Playgroud)

如果您的起点是awk '/b/,/d/' file,请注意另外的语言结构和重复条件:

$ awk '/b/,/d/' file
b
c
d

$ awk '/b/,/d/{if (!/b/) print}' file
c
d

$ awk '/b/,/d/{if (!/d/) print}' file
b
c

$ awk '/b/,/d/{if (!(/b/||/d/)) print}' file
c
Run Code Online (Sandbox Code Playgroud)

此外,它并不明显,但一个阴险的错误悄悄进入上述.请注意此新输入文件中现在位于"c"和"d"之间的附加"b":

$ cat file
a
b
c
b
d
e
Run Code Online (Sandbox Code Playgroud)

并再次尝试从输出中排除第一个边界线:

$ awk 'f; /b/{f=1} /d/{f=0}' file
c
b
d
-> SUCCESS

$ awk '/b/,/d/{if (!/b/) print}' file
c
d
-> FAIL
Run Code Online (Sandbox Code Playgroud)

你实际上需要写这样的东西来继续使用范围并排除第一个边界线

$ awk '/b/,/d/{if (c++) print; if (/d/) c=0}' file
c
b
d
Run Code Online (Sandbox Code Playgroud)

但到那时它显然变得有点傻了,你重写它只是使用像我原来的建议一样的旗帜.