簡體   English   中英

如何在awk程序中使用“ for”?

[英]how to use “for” in awk procedure?

我有一個任務:為存儲在文件中的整數求和編寫一個腳本。 形成呼叫腳本:示例: sum a.txt 3 4

輸入文件可以包含幾列整數。 各個列由規格或制表符分隔。 該腳本應匯總適當的列,並將結果寫入stdout。 因此,當我們得出sum a.txt 3 4時,我們需要添加第三和第四列文件的編號。

所以我這樣做:

#!/bin/bash
array1=( "$@" )
let LA=${#array1[@]}-1
awk '{for(i=1;i<=$LA;i++)y+=$'${array1[i]}'; print y}' a.txt

但我有一個錯誤: awk: : 1unexpected character '.'

請幫忙,是否有另一種方法可以累加過程調用腳本中給出的列數?

在此論壇上,可以執行以下操作:

#!/bin/bash
awk -v col1=$2 -v col2=$3 '{sum1 += $col1; sum2 += $col2} END{print sum1,sum2}' $1

但是,如果我們不知道該過程示例中將提供的列數,該怎么辦: ./sum a.txt 2 3 ... n (也許我需要用於for但如何使用?)

您不需要AWK。 重擊就足夠了:

$ cat data.txt
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
$ ./csum.sh $(seq 0 5) < data.txt
21 24 27 30 33 36
$ cat csum.sh
#! /bin/bash
SUM=()
S=0
for N in "$@"; do
  SUM[$S]=0
  ((S++))
done
while IFS=$'\n' read LINE ; do
  COLS=($LINE)
  S=0
  for C in "$@"; do
    SUM[$S]=$(expr ${SUM[S]} + ${COLS[C]})
    ((S++))
  done
done
echo ${SUM[*]}

好吧,我閱讀了您的最新問題,我想您想要:

file: my.awk

#!/bin/bash
eval "awk '{print \$$2+\$$3}' $1"   

這會將您傳入的列加在一起。

E.g. cat num.txt
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1


$>my.awk num.txt 2 3
7
7
7
7
7
7
7
7
7
7

而且,如果您想要更多列,則可以從命令行中選擇它們,以添加更多列-如下所示添加列4,5,1,3,1,如下所示:

$> my.awk num.txt 4 5+\$1+\$3+\$1
16
16
16
16
16
16
16
16
16
16

值是16,因為第4,5,1,3,1列的相應值為(2 + 1 + 5 + 3 + 5)=16。您可以按任意順序以任意方式附加盡可能多的列,它將將它們全部加在一起。

或者,如果您想要一個更簡單的版本,只需在文件名后加上要添加的列即可:

file: my2.awk

#!/bin/bash
eval "awk '{print $(echo "${*:2}" | sed -r 's/\b[0-9]*\b/\$&+/g;s/\+$//')}' $1"

$> my2.awk num.txt 1 5 2 3
13
13
13
13
13
13
13
13
13
13

awk程序一樣,shell變量不會在單引號引起來的字符串中擴展,您必須使用-v選項后跟var=value來設置變量。

#!/bin/sh
if [ "$#" < 2 ]; then
    echo "$0:" not enough arguments
    exit 1;
fi
FILE=$1;
shift 1;
awk -v A="$*" 'BEGIN { N = split(A,a," "); }\
               { y = 0; for(i = 1; i <= N; i++) y += $(a[i]); print y; }' "$FILE"

shift 1將參數左移1。 $2 -> $1

BEGIN { N = split(A,a," "); } BEGIN { N = split(A,a," "); } split字符串A到一個數組a由空格。

{y = 0; for(i = 1; i <= N; i++) y += $(a[i]); print y; } {y = 0; for(i = 1; i <= N; i++) y += $(a[i]); print y; } y為零,將每個編號為a[i]字段加到y ,最后打印y

但是,您的腳本非常簡單,只需使用awk

#!/usr/bin/awk
BEGIN {
    if (ARGC < 2) {
        print $0, ": not enough arguments";
        exit 1;
    }
    for (i = 2; i < ARGC; i++) {
        a[i] = ARGV[i] + 0;
        delete ARGV[i];
    }
}
{
    tmp = 0;
    for (i in a) {
        tmp += $(a[i]);
    }
    print tmp;
}

a[i] = ARGV[i] + 0a[i]設置為數字 ARGV[i] + 0

delete ARGV[i]刪除ARGV[i] ,這可以防止ARGV[i]被視為要打開的文件名。

可能值得注意的是,大多數awk版本都比bash小很多。

這不是一個完全標記的解決方案。 bash腳本test.sh如下所示:

awk '{for(i=2;i<ARGC;++i)s[i]+=$ARGV[i]}ENDFILE{for(i=2;i<ARGC;++i)printf("%d ",s[i]);print"";exit}' "$@"

輸入項

1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18

命令行:

test.sh inputfile 3 4 5

輸出:

27 30 33

像ARGC [1]這樣的C包含輸入文件的名稱(在這種情況下,它與FILENAME相同),其他大於1的則包含數字。 ENDFILE必須存在,因為沒有3這樣的文件。 但是在此之前,它會打印總和的列值。

參考ceving的評論,純版本就足夠了(如果輸入文件很小,則少於cca 100行)。 在這種情況下,不需要外部實用程序。

file="$1"; shift
cols=($@)
while read -r t; do
  arr=($t)
  for((i=0;i<$#;++i)){ ((sum[i]+=arr[cols[i]-1]));}
done < "$file"
echo "${sum[@]}"

命令行和輸出是相同的。

您忘記提供樣本輸入和預期輸出供我們進行測試,因此這可能對您不起作用,但如果我正確理解您的問題,這是正確的方法:

file="$1"
shift
awk -v fldNrs="$*" '
BEGIN { split(fldNrs,flds) }
{ sum=0; for (idx in flds) sum += $(flds[idx]); print sum }
' "$file"

免責聲明

我的腳本忽略了命令行中的列號重復。

如果OP要求其他行為,則可以使用其他出色的答案來實現其他可能的重復處理。

% cat sum_cols.sh 

file="$1";shift

# next 3 lines, we build, eg, beg="BEGIN{a[3]=0;a[5]=0;a[6]=0;}"
beg="BEGIN{"
for n in "$@"; do beg=$(printf "%sa[%d]=0;" "$beg" "$n") ; done
beg="$beg""}"

# The awk program below  is based on the "for(i in a)" statement
# "for(i in a) is a loop over the indexes of the array "a"
# we loop for every line to accumulate the sum
#         and at the end to print our results

awk "$beg {for(i in a) a[i]+=\$i} END{for(i in a) print i, a[i]}" $file

% cat integers
1 2 3 4 5 6 7 8 9 10 
11 12 13 14 15 16 17 18 19 20 
21 22 23 24 25 26 27 28 29 30 
31 32 33 34 35 36 37 38 39 40 
41 42 43 44 45 46 47 48 49 50 
51 52 53 54 55 56 57 58 59 60 
61 62 63 64 65 66 67 68 69 70 
71 72 73 74 75 76 77 78 79 80 
81 82 83 84 85 86 87 88 89 90 
91 92 93 94 95 96 97 98 99 100 
101 102 103 104 105 106 107 108 109 110 
111 112 113 114 115 116 117 118 119 120 
% sh sum_cols.sh integers 2 5 7
2 684
5 720
7 744
% # EDIT Note that a repeated column number in the command line is ignored 
% sh sum_cols.sh integers 2 5 2 7
2 684
5 720
7 744
% 

編輯

原始問題未定,如果腳本用戶在命令行中重復列號(如上述sh col.sh integers 2 5 2 7 ,該sh col.sh integers 2 5 2 7

我的想法是忽略重復,而在其他解決方案(例如Ed Morton或TrueY的解決方案)中,對於出現n列編號j的結果,您會得到結果n*sum(matrix(i,j), i)

我必須承認,就我而言,選擇一種特定的行為是偶然的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM