0

コマンドを使用して行番号を取得したいの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>
4

4 に答える 4

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コマンドの結果は一連の文字列です。各文字列には、ファイル名、行番号、および行自体が含まれます。コロンで区切ります。
  • 行番号を抽出する 1 つの方法は、最初にコロンをセパレータとして使用して文字列 (結果) を分割することです。次に、lindex2 番目の項目を取得するために使用します (リストは 0 ベースであるため、インデックス = 1)。
  • name=の前に複数のスペースがある場合を考慮して、コードを更新しました。
于 2013-08-12T14:22:08.493 に答える
2

さて、私はあなたのコードと単一の単語パターンにも問題があります!

まず第一に、コマンド自体が最初の引数の評価を行うevalため、コマンドは必要ないと思います。catch

次に、問題は、$textToGrep変数をexec単一引用符'で囲むことです。これは、Tcl にとって意味がありません。

したがって、 の内容が である場合textToGrep、文字列 を検索するfooよう求めています。一重引用符を含むその文字列がファイル内に見つからない場合、エラーが発生します。grep'foo'

最初の行を次のように書き直してみてください

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

そして、それが機能するかどうかを確認してください。execまた、これらの問題を詳しく説明している man ページも読んでください。

于 2013-08-12T10:22:49.407 に答える
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 ステートメントでは、status コマンドを好きなように処理できます。

与えられた例 (あなたの投稿) では、上記のコードは textToGrep 変数の "<" にバックスラッシュを使用するだけで機能します

于 2013-08-12T10:43:06.947 に答える
1

ここには 2 つの問題があります。

  • パターン マッチングが機能しません。
  • child process exited abnormallyパターンが見つからない場合、grep はエラーで終了します

最初の問題は、 (一重引用符ではなく)textToGrep内を囲んでいないためですdouble quotes。したがって、コードは次のようになります。

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

2 番目の問題は、grepコマンドの終了ステータスが原因です。grepパターンが見つからない場合、エラーで終了します。シェルでの試行は次のとおりです。

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

編集:

あなたの場合、 and などの特殊文字が<あります>(シェルでは特別な意味があります)。

set textToGrep  "<BBB name=\"BBBRM\""
regsub -all -- {<} "$textToGrep" "\\\<" textToGrep
regsub -all -- {>} "$textToGrep" "\\\>" textToGrep
于 2013-08-12T10:58:24.513 に答える