首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用grep获取行号

使用grep获取行号
EN

Stack Overflow用户
提问于 2013-08-12 09:43:15
回答 4查看 1.8K关注 0票数 0

我希望使用grep命令获取行号,但当搜索模式不是一个单词时,我将得到错误消息:

代码语言:javascript
运行
复制
couldn't read file "Pattern": no such file or directory

如何正确使用grep?守则如下:

代码语言:javascript
运行
复制
set status [catch {eval exec grep -n '$textToGrep' $fileName} lineNumber]
if { $status != 0 }  {
    #error
} else {
    puts "lineNumber = $lineNumber"
} 

另外,如果搜索模式根本不匹配,则返回的值是:"child process exited abnormally"

下面是简单的测试用例:

代码语言:javascript
运行
复制
 set textToGrep  "<BBB name=\"BBBRM\""

文件内容:

代码语言:javascript
运行
复制
<?xml version="1.0"?>
<!DOCTYPE AAA>
<AAA>
  <BBB name="BBBRM" />
</AAA>
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-08-12 10:58:24

这里有两个问题:

  • 模式匹配无效。
  • 当找不到模式时,grep将以错误child process exited abnormally退出。

第一个问题是,您没有将textToGrep封装在double quotes中(而不是单引号)。所以你的代码应该是:

代码语言:javascript
运行
复制
[catch {exec grep -n "$textToGrep" $fileName} lineNumber]

第二个问题是由于grep命令的退出状态。当找不到模式时,grep会出现错误。下面是对外壳的尝试:

代码语言:javascript
运行
复制
# cat file
pattern
pattern with multiple spaces
# grep pattern file
pattern
pattern with multiple spaces
# echo $?
0
# grep nopattern file
# echo $?
1

编辑:

在您的例子中,您有一些特殊的字符,如<> (它们在shell上有特殊的含义)。

代码语言:javascript
运行
复制
set textToGrep  "<BBB name=\"BBBRM\""
regsub -all -- {<} "$textToGrep" "\\\<" textToGrep
regsub -all -- {>} "$textToGrep" "\\\>" textToGrep
票数 1
EN

Stack Overflow用户

发布于 2013-08-12 10:22:49

嗯,我也遇到了你的代码和一个单词模式的问题!

首先,我认为您不需要eval命令,因为catch本身对其第一个参数进行了计算。

然后,问题是您将$textToGrep变量放入exec中的单引号'中,这对Tcl没有任何意义。

因此,如果textToGrep的内容是foo,则要求grep搜索字符串'foo'。如果该字符串(包括单引号)未在文件中找到,则会得到错误。

试着用

代码语言:javascript
运行
复制
set status [catch {exec grep -n $textToGrep $fileName} lineNumber]

看看能不能用。另外,请阅读exec手册页,它很好地解释了这些问题。

票数 2
EN

Stack Overflow用户

发布于 2013-08-12 14:22:08

如果您的系统有tcllib安装,可以使用来自fileutil包的fileutil命令:

代码语言:javascript
运行
复制
package require fileutil

set fileName data.xml
set textToGrep {<BBB +name="BBBRM"}; # Update: Add + for multi-space match
set grepResult [::fileutil::grep $textToGrep $fileName]
foreach result $grepResult {
    # Example result:
    # data.xml:4:  <BBB name="BBBRM" />
    set lineNumber [lindex [split $result ":"] 1]
    puts $lineNumber

    # Update: Get the line, squeeze the spaces before name=
    set line [lindex [split $result ":"] 2]
    regsub { +name=} $line " name=" line
    puts $line
}   

讨论

  • 当将值赋值给textToGrep时,我使用了大括号,从而允许内部引用双引号,而不必转义它们。
  • ::fileutil::grep命令的结果是字符串的lits。每个字符串包含文件名、行号和行本身;用冒号分隔。
  • 提取行号的一种方法是使用冒号作为分隔符,首先将字符串(结果)拆分为几个部分。接下来,我使用lindex获取第二项(index=1,因为列表是零基的)。
  • 我已经更新了代码,以说明在name=之前有多个空格的情况。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18183901

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档