[英]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] + 0
將a[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的評論,純bash版本就足夠了(如果輸入文件很小,則少於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.