【问题标题】:Bash print file contents between two stringsBash 在两个字符串之间打印文件内容
【发布时间】:2021-03-23 17:09:51
【问题描述】:
a
b
s
start
text
more text
end
even more text
end

我想打印startstart 之后的第一个end 之间的内容(start 始终是唯一的)。我还想在打印文本的行之间打印,在本例中是在第 4 行和第 7 行之间。

我正在尝试使用grepcat,但我做不了什么。

我试过了:

var=$(cat $path)
echo "$var" | grep -o -P '(?<=start).*(?=end)'

但它没有打印任何内容,没有grep,它会打印整个文件。

这个例子中的输出应该是:

The content is between lines 4 and 7.

start
text
more text
end

【问题讨论】:

  • 请在您的问题中添加您的努力,这是非常鼓励的,谢谢。
  • 您想在输出中打印行和行号吗?请使用代码格式块中的预期输出更新问题;

标签: bash shell awk grep cat


【解决方案1】:

将shell变量传递给awk,然后按范围打印文本,然后尝试,在awkstart变量中提及你的shell变量,那么我们应该很好。 (也可以将 $0 ~ start 更改为 $0 ~ "^"start"$",以防您想在行中查找起始值的完全匹配。)

awk -v start="$your_shell_start_var" '
$0 ~ start,$0 ~ /^end$/{
  print
  if($0 ~ start){ startLine=FNR }
  if($0~/^end$/){ 
     print "The content is between lines " startLine " and " FNR
     exit
  }
}' Input_file

OP 样本的样本输出:

start
text
more text
end
The content is between lines 4 and 7

简单解释: 在此语句之间按范围打印行 startend 检查条件是否行有结束字符串然后从 Input_file 中出来,我们不需要读取完整的 Input_file,因为 OP 只需要打印第一组行。

【讨论】:

  • 我认为它会读到文件的末尾,而不是在“结束”处停止。它从正确的位置开始。
  • @GeoCap,如果您的行与end 完全相同(此处不考虑行尾或行首或任何其他单词的任何空格),那么它将打印第一组的匹配值。假设开始变量是bla,那么它应该打印从blaend(第一次出现)的值,然后从文件中出来,如果有任何查询或它不起作用,请告诉我。
  • 对我来说,带有变量的示例打印从变量和整个文件开始的文件(不会在“结束”处停止)。没有变量的示例确实在“结束”处停止,并测试了相同的文件。
  • 哦,是的,我有空行,抱歉,现在可以了,谢谢!
  • 是的,感谢您的帮助,因为我的问题已经解决了一半,我仍然想打印提取内容的行数。
【解决方案2】:

样本数据:

$ cat -n strings.dat
 1  a
 2  b
 3  s
 4  start
 5  text
 6  more text
 7  end of more text
 8  end
 9  even more text
10  end

一个awk 解决方案使用一个范围(类似于 RavinderSingh13 的帖子),在末尾打印出 OP 的文本消息:

startstring="start"                            # define start of search block

awk -v ss="${startstring}" '                   # pass start of search block in as awk variable "ss"

# search for a range of lines between "ss" and "end":

$0==ss,/^end$/ { if ($0==ss && x==0 ) x=FNR    # if this is the first line of the range make note of the line number
                 print                         # print the current line of the range
                 if ($0=="end")                # if this is the last line of the range then print our textual message re: start/finish line numbers
                    printf "\nThe content is between lines %d and %d.\n",x,FNR
               }
' strings.dat

注意$0==ss/^end$/ 测试假定数据文件中没有前导/尾随空格,否则这些测试将失败并且没有范围匹配。

使用startstring="start" 会生成:

start
text
more text
end of more text
end

The content is between lines 4 and 8.

使用startstring="more text" 会生成:

more text
end of more text
end

The content is between lines 6 and 8.

使用startstring="even more text" 会生成:

even more text
end

The content is between lines 9 and 10.

使用startstring="water" 会生成:

--no output--

注意:如果 OP 使用startstring="end",结果与预期不符;虽然可以添加更多代码来解决这种情况,但我将暂时跳过这种情况。

【讨论】:

  • 如果你打算使用出口,你也可以在发出出口之前打印摘要,不再需要 END 块。
  • 当然,这对于缩短版来说确实是个好主意;谢谢
  • 它对我不起作用。我应该补充一点,文件中可能有空格,如果重要的话,文件是 .cpp
  • 你必须详细说明didn't work for me;文件名/扩展名无关紧要,重要的是我们需要准确描述所述文件内容的文件内容(即,用更多细节更新问题)
猜你喜欢
  • 1970-01-01
  • 2012-09-10
  • 1970-01-01
  • 1970-01-01
  • 2021-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-15
  • 1970-01-01
相关资源
最近更新 更多