【问题标题】:Reading through a text file line by line and checking if that line has a certain string逐行读取文本文件并检查该行是否有某个字符串
【发布时间】:2015-06-24 15:25:03
【问题描述】:

我正在尝试使用 Shell 脚本逐行读取文本文件。我一直在做的是

while read line
do
   var1=$(grep -s "Completed" $line)
   var2=$(grep -s "Script Finished" $line)

if[ "$var1" = "$line" ]
   break
else
   if[ "$var2" = "$line" ]
       count='expr $count + 1'
   else
      countinue
   fi
fi
done < file.txt

如果您有任何建议,请告诉我!我对其他选择持开放态度,因为我一直在尝试这样做太久。

澄清:

我正在逐行浏览文件(while 循环),然后我正在查找该行以查看“已完成”是否为子字符串,并查看“脚本已完成”是否为子字符串(Grep 会将变量设置为整条线)。因此,当我检查变量是否已完成时,如果不检查“脚本完成”是否是子字符串,我想跳出 while 循环,这样我就可以增加一个计数器(我试图计算在“之前完成了多少脚本”完成”)。

困惑:

当我做 var1=$(grep -s "Completed" $line) 为什么它会找到 Completed 的所有实例...我想如果我逐行遍历它只会找到该特定行中的实例。

编辑:

我使用了下面的 awk 答案。我所要做的就是删除 {next} 语句,它可以完美运行。

谢谢

【问题讨论】:

  • 你想用这个实现什么?您能提供一些相关信息吗?
  • 是的,当然我很抱歉。我正在尝试浏览一个列出脚本运行时间的文件。所以我只关心脚本是否完成..如果它完成了,我会增加计数器。但是,脚本是分块运行的。早上下午和晚上。所以我用“blah blah”(脚本完成)打破循环,因为这将是早上完成的脚本数量
  • 如果您不尝试一次全部完成,而是专注于使各个部分工作,那么您将更轻松地执行此操作并找到相关资源。例如,您应该定义两个字符串 a="hello world" b="panda" 并尝试编写一个比较它们的 if 语句(然后设置 b=$a 以确保正面和负面情况都有效)。谷歌“如何比较 shell 脚本中的字符串”比“如何逐行读取文本文件,检查该行是否有特定字符串”要容易得多。
  • 我想我最重要的问题是,如果我将 grep 设置为变量,它会返回什么。
  • Grep 返回那个,无论如何它会返回什么。不管你是否指向一个变量。

标签: linux shell unix scripting


【解决方案1】:

我在(当前)接受的解决方案之后发布此内容,因为接受的解决方案使用标签未涵盖的语言。

你可以在 shell 中使用 case 语句来做同样的事情。 (虽然对于大文件,awk 或 grep 可能更快)

while read line; do
case "$line" in 
   *"Completed"*)break;;
   *"Script Finished"*)count=$((count + 1));;
esac
done < file.txt

注意:这种形式的while read line; ... 会省略最后一行,如果不行,请使用while read line || [ "$line" ](这是一些IDE 会在文件末尾添加一个空的新行的原因之一)

【讨论】:

  • 哦,我没听懂!谢谢
【解决方案2】:

错误 #1:

当我做 var1=$(grep -s "Completed" $line) 为什么它找到所有 Completed 的实例

在上述命令中,grep 期望 $line 是文件名而不是字符串。如果要传递字符串,则需要使用管道:

var1=$(echo "$line" | grep -s "Completed")

或者在 Bash 中你可以使用字符串重定向:

var1=$(grep -s "Completed" <<<"$line")

错误 #2:

if[之间应该有空格([test命令)


这个grep 命令可能会与您尝试使用该代码执行相同的操作:
grep -v "Completed" file.txt | grep -c "Script Finished"

grep -v "Completed" file.txt 返回不包含“Completed”的行,并通过管道发送到下一个grep,该管道返回包含文本“Script Finished”的行数。

【讨论】:

  • 感谢您的澄清。以及使用 grep 的巧妙方法。
【解决方案3】:

您有几个错误。另外,您可能需要考虑一种旨在执行此类操作的工具。 awk 就是其中一种工具。

awk '/blah blah/ {exit} 
     /Finished/ {count+=1} 
     {next}
     END{ print count} ' filename

当第一行匹配“blah blah”时,第一行退出。​​

第二行计算“已完成”匹配的数量。

{next} 位用于继续阅读而不是打印每一行 - 这发生在某些版本的 awk 中。

最后一行 END {} 函数在代码完成文件时运行。它显示计数的值。

我选择了 awk 方法,而不是尝试修复 shell 脚本中的逻辑和语法错误。如果您需要这种帮助,请考虑在命令行上单独播放几乎所有代码块(或行)。我假设你使用了 bash。

错误示例

-eq to compare strings, use =, example:  [ "$var" = "something" ]
$(var1) should be either "${var1}" or "$var1" lines 4 and 8

grep 返回一整行,您是否在测试“blah blah”并期望仅且仅“blah blah”作为整个结果?

【讨论】:

  • 我现在要试试这个。谢谢你的回答,我会让你知道会发生什么。我正在针对 $line 测试 grep blah blah $line .. 但你的方式似乎好多了。听说 awk 可以轻松替换 grep。
  • awk '/Completed/ {exit} /Finished/ {count+=1} {next} END{ print count} ' filename 似乎陷入了无限循环
  • 知道了!非常感谢。
  • 现在我正在尝试在 awk 命令中添加更多条件。我有awk ' / Completed/ { counter +=1} Finished/ { if (counter = 1) mornCount +=1 if (counter =2) afterCount+=1 and if(counter=3) nightCounter+=1} END{ print morn, after, and night counters}
猜你喜欢
  • 2018-07-30
  • 1970-01-01
  • 2017-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-29
  • 1970-01-01
  • 2017-05-05
相关资源
最近更新 更多