1

File_A には 135 のドキュメントが 135 行 (つまり、各行は長いテキスト) として格納されており、File_B には 15 のフレーズがあります。File_B の一致するフレーズを使用して、File_A から文とその前を抽出する必要があります。File_A-Line_1 から抽出された文は、新しいファイル File_1 に出力されます。同様に、File_A-Line_2 から抽出された文は、すべての行から一致する文を抽出するまで、新しいファイル File_2 に出力する必要があります。私は次のコードでこれを行いました

i=1
while read line; do
 while read row; do
   cat "$line" | sed 's/\./.\n/g' | grep -i -B 1 "$row"  | tr -d '\n' |  sed 's/--/\n/g'    >> file_$i
 done < $2 
 $i = $i+1;
done < $1

ここでの問題は、出力がコンソールに出力されますが、新しいファイルには出力されないことです。誰かが私のエラーを理解するのを手伝ってくれませんか。

ありがとうございました

4

4 に答える 4

1

前述の問題 ( の再インクリメントiと誤用cat) を修正すると、次のような結果になります。date > file_$iテストの開始時に各出力ファイルが新しいことを確認するために、この行はデバッグ用にあることに注意してください。:オペレーターはノーオペレーションです。フォーム<<<は「ヒアドキュメント」を導入します。の内容が$linesファイル名である場合、質問で指定されているドキュメントではなく、代わりに を使用<"$lines"<<<"$lines"ます。

#!/bin/bash
i=1
while read line; do
    date > file_$i
    while read row; do
    sed 's/\./.\n/g' <<< "$line" | grep -iB1 "$row" | tr -d '\n' |  sed 's/--/\n/g' >> file_$i
    done < $2 
    : $((i++))
done < $1

以下を含む splitdoc.data が与えられた場合:

This is doc 1.  I am 1 fine.  How are you, 1.? Ok. Hello 1.--  Go away now.
This is doc 2.  I am 2 fine.  How are you, 2.? Ok. Hello 2.--  Go away now.
This is doc 3.  I am 3 fine.  How are you, 3.? Ok. Hello 3.--  Go away now.
This is doc 4.  I am 4 fine.  How are you, 4.? Ok. Hello 4.--  Go away now. 

および splitdoc.tags は次のとおりです。

How are you
Go away now

次に、コマンド

./splitdoc.sh splitdoc.data splitdoc.tags ; head file_*

生成:

==> file_1 <==
Fri Oct 26 19:42:00 MDT 2012
  I am 1 fine.  How are you, 1. Hello 1.
  Go away now.
==> file_2 <==
Fri Oct 26 19:42:00 MDT 2012
  I am 2 fine.  How are you, 2. Hello 2.
  Go away now.
==> file_3 <==
Fri Oct 26 19:42:00 MDT 2012
  I am 3 fine.  How are you, 3. Hello 3.
  Go away now.
于 2012-10-27T01:46:15.327 に答える
1

これは、シェルで変数をインクリメントする方法ではありません。

$i = $i + 1

代わりに、名前が の現在の値であるコマンドを実行しようとします$i。あなたはこれを求めている:

let i=i+1

または、より簡潔に言うと、

let i+=1

これは問題ではないかもしれませんが、問題であり、奇妙な動作につながる可能性があります。

"$1"他に唯一見られるのは、ファイル名 ( , )の周りに引用符がないことです"$2"

また、各行がファイル名の場合は必要ありませんcat; ただする

<"$line" sed ...

各行が名前ではなくファイルの内容である場合、cat名前がその長い長いテキストであるファイルを見つけようとするため、完全に間違っています。代わりにこれを使用できます:

<<<"$line" sed ...

EDITまた、fileB にそれほど多くの行がない場合は、fileA にリストされているすべてのファイルについて何度も何度も読み取ることを避けることができる場合があります。fileB のすべてを一度にメモリに読み込むだけです。

IFS=$'\n' rows=($(<"$2"))
let i=0
while read line; do
  for row in "${rows[@]}"; do
    <<<"$line" sed 's/\./.\n/g' | grep -i -B 1 "$row"  | 
             tr -d '\n' |  sed 's/--/\n/g' >> file_$i
  done 
  let i+=1
done < "$1"

実際、1 回の grep で実行できる場合もあります。

pat=''
while read row; do
  pat="${pat:+$pat|}$row"
done <"$2"

let i=0
while read line; do
  <<<"$line" sed 's/\./.\n/g' | egrep -i -B 1 "$pat"  | 
             tr -d '\n' |  sed 's/--/\n/g' >"file_$i"
let i+=1
done < "$1"
于 2012-10-27T01:32:16.013 に答える
1

これは明らかですか?そうでない場合は、コメントしてください。編集します。Bash 出力リダイレクトの例:

echo "some text" >file.txt;
#here we add on to the end of the file instead of overwriting the file
echo "some additional text" >>file.txt;
#put something in two files and output it
echo "two files and console" | tee file1.txt | tee file2.txt;
#put something in two files and output nothing
echo "just two files" | tee file1.txt >file2.txt;
于 2012-10-27T01:36:15.447 に答える
1

これはうまくいくと思います

i=1
while read line; do
 while read row; do
   echo "$line" | sed 's/\./.\n/g' | grep -i -B 1 "$row"  | tr -d '\n' |  sed 's/--/\n/g' >> file_$i
 done < $2 
 $i = $i+1;
done < $1 

a=0 
while read line; do 
a=$(($a+1)); 
while read row; do
    echo "$line" | sed 's/\./.\n/g' | grep -i -B 1 "$row" | tr -d '\n' | sed 's/--/\n/g' >> file_$a done < $2 done < $1
于 2012-10-27T01:14:00.663 に答える