GAWK 在 FOR 中连接变量
GAWK concat variables in FOR
我当前的 GAWK 脚本获取短语文件,并创建正则表达式模式数组,然后用 \t 字符拆分每一行并循环每行的前 10 列,然后检查它是否至少包含模式数组中的一个短语, 如果是,它会跳过该行并且不会将其打印到文档中。
问题:
因为短语文件很大,它会产生大量的迭代并使脚本非常慢。
(700 patterns x 10 columns (separated by tab \t)) x 1000 of rows.
解决方案:
为了提高速度,我想连接前 10 列,并检查整个字符串是否至少包含一个模式。我不知道如何在 FOR 循环中连接行。
工作示例:
gawk 'BEGIN{
FS=" *\t *";
IGNORECASE=1;
while(getline a < "'$phpath'") PATS["^.*"a".*$"]
}
{
ok=1;
for(i=1;i<=10;i++){
for(p in PATS){
if($i ~ p){
ok=0
}
}
}
}
ok {print}' "$f" > "$newPath$filename"
我的尝试:
gawk 'BEGIN{
FS=" *\t *";
IGNORECASE=1;
while(getline a < "'$phpath'") PATS["^.*"a".*$"]
}
{
phrase="";
space=" ";
ok=1;
for(i=1;i<=10;i++){
phrase = $space $phrase $i
}
for(p in PATS){
if($phrase ~ p){
ok=0
}
}
} ok {print}' "$f" > "$newPath$filename"
在 awk 中,您使用 $
就像 取消引用运算符 ,其中 $x
表示 "give me the value of the column whose number is in variable x
"
要将前 10 列放入字符串中:
for (i=1; i<=10; i++) {
# not this => phrase = $space $phrase $i
phrase = space phrase $i
}
和
for (p in PATS) {
if (phrase ~ p) { # <= no $
ok = 0
break # no match, so break the loop early
}
}
awk 使用像 C 那样的变量,而不像 shell 或 perl
您也可以试试这个:
gawk -v patternfile="$phpath" '
BEGIN {
FS = " *\t *"
IGNORECASE = 1
while ((getline a < patternfile) > 0)
PATS["^.*"a".*$"]
}
{
line = [=12=]
NF = 10 # this truncates the current record to 10 fields
ok = 1
for (p in PATS)
if ([=12=] ~ p) {
ok = 0
break
}
if (ok)
print line
}
' "$f" > "$newPath$filename"
这不是您问题的答案,但可能是您的问题。
我了解到您的问题与性能有关。
据我了解,您遇到的主要问题之一是您使用的是 RegEx。让我解释一下我的观点。在 AWK 中,当你使用像这样的正则表达式时:/MyRegExp/,你使用的是正则表达式的编译版本,所以每次你需要检查匹配时,你只检查它,但是当你像这样使用正则表达式时:"MyRegExp",每次你想检查一个字符串是否匹配时都会编译它。
你真的在检查 RegEx 吗?也许你不是,函数 'index' 对你来说已经足够好了。
您为什么不尝试构建一个脚本并 运行 它呢?而不是根据加载的模式检查第二个文件中的每一行,而是创建如下脚本:
/pattern1/{
print
next
}
/pattern2/{
print
next
}
/pattern3/{
print
next
}
...
...
然后 运行 它与第二个文件。总之,希望对大家有所帮助。
while(getline a < "'$phpath'") PATS["^.*"a".*$"]
RE ^.*"a".*$
等同于 a
。您可以直接使用 |
声明 OR 条件,而不是遍历模式。
如果您的输入文件是
every
good
boy
does
fine
你的 RE 变成了 every|good|boy|does|fine
而你的代码缩减为
[=12=] ~ pattern {
for (i=1; i<=10; i++) {
if( $i ~ pattern ) {
print "$f" > "$newPath$filename" # what's $f?
break
}
}
}
即先整行扫描。如果找到某些内容,则遍历前 10 列。我敢打赌这比无条件地迭代它们要快。
我当前的 GAWK 脚本获取短语文件,并创建正则表达式模式数组,然后用 \t 字符拆分每一行并循环每行的前 10 列,然后检查它是否至少包含模式数组中的一个短语, 如果是,它会跳过该行并且不会将其打印到文档中。
问题:
因为短语文件很大,它会产生大量的迭代并使脚本非常慢。
(700 patterns x 10 columns (separated by tab \t)) x 1000 of rows.
解决方案:
为了提高速度,我想连接前 10 列,并检查整个字符串是否至少包含一个模式。我不知道如何在 FOR 循环中连接行。
工作示例:
gawk 'BEGIN{
FS=" *\t *";
IGNORECASE=1;
while(getline a < "'$phpath'") PATS["^.*"a".*$"]
}
{
ok=1;
for(i=1;i<=10;i++){
for(p in PATS){
if($i ~ p){
ok=0
}
}
}
}
ok {print}' "$f" > "$newPath$filename"
我的尝试:
gawk 'BEGIN{
FS=" *\t *";
IGNORECASE=1;
while(getline a < "'$phpath'") PATS["^.*"a".*$"]
}
{
phrase="";
space=" ";
ok=1;
for(i=1;i<=10;i++){
phrase = $space $phrase $i
}
for(p in PATS){
if($phrase ~ p){
ok=0
}
}
} ok {print}' "$f" > "$newPath$filename"
在 awk 中,您使用 $
就像 取消引用运算符 ,其中 $x
表示 "give me the value of the column whose number is in variable x
"
要将前 10 列放入字符串中:
for (i=1; i<=10; i++) {
# not this => phrase = $space $phrase $i
phrase = space phrase $i
}
和
for (p in PATS) {
if (phrase ~ p) { # <= no $
ok = 0
break # no match, so break the loop early
}
}
awk 使用像 C 那样的变量,而不像 shell 或 perl
您也可以试试这个:
gawk -v patternfile="$phpath" '
BEGIN {
FS = " *\t *"
IGNORECASE = 1
while ((getline a < patternfile) > 0)
PATS["^.*"a".*$"]
}
{
line = [=12=]
NF = 10 # this truncates the current record to 10 fields
ok = 1
for (p in PATS)
if ([=12=] ~ p) {
ok = 0
break
}
if (ok)
print line
}
' "$f" > "$newPath$filename"
这不是您问题的答案,但可能是您的问题。
我了解到您的问题与性能有关。
据我了解,您遇到的主要问题之一是您使用的是 RegEx。让我解释一下我的观点。在 AWK 中,当你使用像这样的正则表达式时:/MyRegExp/,你使用的是正则表达式的编译版本,所以每次你需要检查匹配时,你只检查它,但是当你像这样使用正则表达式时:"MyRegExp",每次你想检查一个字符串是否匹配时都会编译它。
你真的在检查 RegEx 吗?也许你不是,函数 'index' 对你来说已经足够好了。
您为什么不尝试构建一个脚本并 运行 它呢?而不是根据加载的模式检查第二个文件中的每一行,而是创建如下脚本:
/pattern1/{
print
next
}
/pattern2/{
print
next
}
/pattern3/{
print
next
}
...
...
然后 运行 它与第二个文件。总之,希望对大家有所帮助。
while(getline a < "'$phpath'") PATS["^.*"a".*$"]
RE ^.*"a".*$
等同于 a
。您可以直接使用 |
声明 OR 条件,而不是遍历模式。
如果您的输入文件是
every
good
boy
does
fine
你的 RE 变成了 every|good|boy|does|fine
而你的代码缩减为
[=12=] ~ pattern {
for (i=1; i<=10; i++) {
if( $i ~ pattern ) {
print "$f" > "$newPath$filename" # what's $f?
break
}
}
}
即先整行扫描。如果找到某些内容,则遍历前 10 列。我敢打赌这比无条件地迭代它们要快。