我在file_a中存储了135个文档为135行(因此每行都是长的文本),我在file_b中有15个短语。我需要从file_b中的匹配短语从file_a提取句子及其之前。从file_a-line_1提取的句子应输出到新的文件file_1。同样,从file_a-line_2提取的句子应输出到新的文件_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
这里的问题是,输出被打印到控制台上,而不是在新文件上。有人可以帮助我意识到自己的错误。
谢谢
这很清楚吗?如果没有,请对其发表评论,我将编辑它。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;
解决以前提到的问题(重新递增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.
我认为这会起作用
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
这不是您在外壳中增加变量的方式:
$i = $i + 1
试图运行名称是$i
的当前值的命令。您想要这个:
let i=i+1
或更简单地,
let i+=1
这可能不是问题,但这是一个问题,它可能导致奇怪的行为。
我唯一看到的另一件事是您的文件名缺乏引号("$1"
,"$2"
)。
另外,如果每行都是文件名,则不需要cat
;只是做
<"$line" sed ...
如果每行是文件的内容而不是名称的内容,则cat
是完全错误的,因为它试图找到一个名称为大文本的文件。您可以使用此方法:
<<<"$line" sed ...
编辑,如果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"
实际上,您甚至可以在一个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"
tee
实际上接受多个文件参数,因此很简单:
# from file
tee 1.txt 2.txt 3.txt <0.txt
# from string
tee 1.txt 2.txt 3.txt <<<'text'
# from heredoc
tee 1.txt 2.txt 3.txt <<'EOF'
line
line
line
EOF
# from pipeline
command | tee 1.txt 2.txt 3.txt