2013-08-12 2 views
0

Я хотел бы получить номер строки, используя grep команду, но я получаю сообщение об ошибке, когда шаблон поиска не одно слово:Получить номер строки с помощью Grep

couldn't read file "Pattern": no such file or directory 

Как должно быть надлежащее использование grep? Код здесь:

set status [catch {eval exec grep -n '$textToGrep' $fileName} lineNumber] 
if { $status != 0 } { 
    #error 
} else { 
    puts "lineNumber = $lineNumber" 
} 

Кроме того, если шаблон поиска не соответствует вообще, возвращаемое значение: "child process exited abnormally"

Вот простой тест:

set textToGrep "<BBB name=\"BBBRM\"" 

содержимое файла:

<?xml version="1.0"?> 
<!DOCTYPE AAA> 
<AAA> 
    <BBB name="BBBRM" /> 
</AAA> 
+0

Можете ли вы дать содержимое переменных '' textToGrep', filename'? Также содержимое файла? – Varun

ответ

1

Есть две проблемы: согласование

  • Pattern не работает.
  • Grep завершается с ошибкой child process exited abnormally, когда шаблон не найден

Первая проблема в том, что вы не заключени textToGrep в double quotes (вместо одиночных кавычек). Так что ваш код должен быть:

[catch {exec grep -n "$textToGrep" $fileName} lineNumber] 

Вторая проблема из-за состояния выхода grep команды. grep выходит с ошибкой, когда шаблон не найден.Вот попытка на раковине:

# cat file 
pattern 
pattern with multiple spaces 
# grep pattern file 
pattern 
pattern with multiple spaces 
# echo $? 
0 
# grep nopattern file 
# echo $? 
1 

EDIT:

В вашем случае у вас есть специальные символы, такие как < и > (которые имеют особое значение на скорлупе).

set textToGrep "<BBB name=\"BBBRM\"" 
regsub -all -- {<} "$textToGrep" "\\\<" textToGrep 
regsub -all -- {>} "$textToGrep" "\\\>" textToGrep 
+0

Спасибо за ответ. Но я все равно получаю ту же ошибку: не удалось прочитать файл «

+0

Это потому, что '<' and '>' несут особое значение в оболочке. Я отредактировал свой ответ с решением. – Varun

2

Ну, у меня также возникают проблемы с вашим кодом и одним словом!

Прежде всего, я не думаю, что вам нужна команда eval, потому что catch сам выполняет оценку своего первого аргумента.

В этом случае проблема заключается в том, что вы помещаете переменную $textToGrep в exec внутри одинарных кавычек ', которые не имеют значения для Tcl.

Таким образом, если содержание textToGrep равно foo, вы запрашиваете grep для поиска строки 'foo'. Если эта строка, включая одинарные кавычки, не найдена в файле, вы получите ошибку.

Попробуйте переписать первую строку с

set status [catch {exec grep -n $textToGrep $fileName} lineNumber] 

и посмотреть, если он работает. Кроме того, прочитайте справочную страницу exec, которая хорошо объясняет эти проблемы.

+0

Я все еще получаю ту же ошибку –

+0

Вы уверены, что файл содержит то, что вы ищете? Глядя на man-страницу 'exec', у вас есть пример проверки этого, используя либо' try ... except', либо 'catch'. Когда шаблон не найден в файле, 'grep' выходит с ненулевым результатом, а ваш скрипт показывает ошибку. –

+0

Несомненно, шаблон, который я ищу, находится в файле. Я получаю ошибку следующим образом: не удалось прочитать файл «шаблон, который должен быть поиск»: нет такого файла или каталога –

1
set textToGrep {\<BBB name="BBBRM"} 
catch {exec grep -n $textToGrep $fileName} status 
if {![regexp "child process" $status]} { 
puts $status 
} else { 
puts "no word found" 
} 

Я думаю, что вы должны делать регулярное выражение с дочерним процессом. Просто проверьте код выше, если он работает. В инструкции if вы можете обрабатывать команду статуса по своему усмотрению.

С данного примера (в вашем посте) выше код работает только вы должны использовать обратную косую черту для «<» в textToGrep переменной

2

Если ваша система имеет tcllib установку, вы можете использовать команду fileutil::grep из fileutil пакета:

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 является строкой строк. Каждая строка содержит имя файла, номер строки и сама строка; разделенных двоеточием.
  • Один из способов извлечь номер строки - сначала разбить строку (результат) на куски, используя двоеточие в качестве разделителя. Затем я использую lindex, чтобы захватить второй элемент (index = 1, поскольку список равен нулю).
  • Я обновил код, чтобы учесть случай, когда есть несколько пробелов перед именем =
+0

Есть ли способ обрезать пробелы, перед grep из xml (хотя это не связано с этим вопросом)? –

+0

Вы имели в виду подрезку белого пробела от '', поэтому он становится ''? –

+0

Я имею в виду обрезать пробелы перед атрибутами: so

Смежные вопросы