[编辑:阐明了我需要awk解决方案,并且更正了我需要对'索引'进行排序(或者,以排序的方式输出),而不是模棱两可的'值'))
在awk中,我经常使用数组中的值作为索引来计算事物或在数组中存储一组值(利用awk的indexs_are_hashes机制)
例如:如果我想知道$ 2遇到了多少个不同的值,以及每个值出现的频率:
awk '
... several different treatments ...
{ count[$2]++ }
... other treatments ...
END { for(str in count) {
print "counted: " str " : " count[str] " times."
... and other lines underneath, with additional infos ...
}
}
'
问题是(非GNU或其他更好的版本)常规awk(和常规nawk):
对于[A]:不太难做..只需使用另一个数组来索引“新近看到”的条目。
问题是针对[B]的:如何进行简单的排序以重新排序不同索引的显示?
(注意:我知道gnu awk对于[B]有一种“简便”的方法:https : //www.gnu.org/software/gawk/manual/html_node/Controlling-Array-Traversal.html ...但是我想要在常规awk / nawk中做类似的事情!)
(即:我需要做一个循环来输出所看到的不同索引,对它们进行排序,在旧的awk中将它们重新读取为“ something”(例如:另一个数组ordered_seen吗?),并使用该东西来显示看到的按选择的顺序排列。这需要在awk内,因为在每个索引下,我经常需要输出一段附加信息。awk之外的“排序”将对所有内容进行重新排序)
到目前为止:我发现没有“公理化”的单线(或n线?)方式可以做到这一点。
我最终得到了一条占用几行的句柄,通过排序将每个值输出到一个文件,然后重新读取排序的文件,并将每一行按顺序插入到sorted_countindexes [n ++]中,然后for(i = 0; i <= n; i ++){...输出计数[sorted_countindexes [n]] ...}
我欢迎更好/更简单/更多的“公理化”根据常规awk(或nawk)根据索引输出索引
MCVE:这是一个简单的示例:以字母顺序输出索引会非常好:
# create the 2 basic files to be parsed by the awk:
printf 'a b a a a c c d e s s s s e f s a e r r f\ng f r e d e z z c s d r\n' >fileA
printf 's f g r e d f g e z s d v f e z a d d g r f e a\ns d f e r\n'>fileB
# and the awk loop: It outputs in 'whatever order', I want in 'alphabetical order'
for f in file? ; do printf 'for file: %s: ' "$f"
tr ' ' '\n' < "$f" | awk '
{ count[$0]++ }
END { for(str in count){
printf("%s:%d ",str,count[str])
}; print ""
} '
done
#this outputs:
for file: fileA: d:3 e:5 f:3 g:1 r:4 s:6 z:2 a:5 b:1 c:3
for file: fileB: d:5 e:5 f:5 g:3 r:3 s:3 v:1 z:2 a:2
# I'd like to have the letters outputted in alphabetical order instead!
$ cat tst.awk
{ cnt[$0]++ }
END {
n = sort(cnt,idxs)
for (i=1; i<=n; i++) {
idx = idxs[i]
printf "%s:%d%s", idx, cnt[idx], (i<n ? OFS : ORS)
}
}
function sort(arr, idxs, args, i, str, cmd) {
for (i in arr) {
gsub(/\047/, "\047\\\047\047", i)
str = str i ORS
}
cmd = "printf \047%s\047 \047" str "\047 |sort " args
i = 0
while ( (cmd | getline idx) > 0 ) {
idxs[++i] = idx
}
close(cmd)
return i
}
# create the 2 basic files to be parsed by the awk:
printf 'a b a a a c c d e s s s s e f s a e r r f\ng f r e d e z z c s d r\n' >fileA
printf 's f g r e d f g e z s d v f e z a d d g r f e a\ns d f e r\n'>fileB
for f in fileA fileB ; do
printf 'for file: %s: ' "$f"
tr ' ' '\n' < "$f" |
awk -f tst.awk
done
for file: fileA: a:5 b:1 c:3 d:3 e:5 f:3 g:1 r:4 s:6 z:2
for file: fileB: a:2 d:5 e:5 f:5 g:3 r:3 s:3 v:1 z:2
上面的代码只是从数组索引中构建一个以换行符分隔的字符串(用适当地引用它sh
),创建一个Shell脚本,将该字符串通过管道传递到sort
,然后在输出中循环。如果要修改sort
s的行为,只需sort
在sort
函数调用中添加Unix参数字符串即可,例如sort(seen,"-fu")
。很明显,可以修改它以打印或在sort()
函数中执行任何您想做的事情,而不是填充一个索引数组,以便在返回时循环返回(如果您希望这样做,则该函数具有内聚性)。
但是请注意,它将限于系统上的最大命令行长度。
\047
代码中的s表示'
s哪个shell不允许包含在-定'
界的字符串或脚本中,因此,尽管我们可以'
像上面那样在从文件中读取的awk脚本中直接使用它,但是如果您要使用的话命令行上的脚本,因为当awk 'script' file
您从命令行和文件中解释脚本时,您需要使用某些脚本来代替脚本,'
并且\047
脚本都可以工作,因此这是'
-replacement的最可移植的选择。
在'
S(\047
S)存在引用str
的方式,确保外壳不展开变量,有不匹配的报价等当字符串是被管道进行排序,即他们这样做:
$ echo 'foo'\''bar $(ls) $HOME' | awk '{
str=$0; gsub(/\047/, "\047\\\047\047", str); print "str="str
cmd="printf \047%s\047 \047" str "\047"; print "cmd="cmd
}'
str=foo'\''bar $(ls) $HOME
cmd=printf '%s' 'foo'\''bar $(ls) $HOME'
因此,我们不会得到像这样的脆弱/越野车:
$ echo 'foo'\''bar $(ls) $HOME' | awk '{
str=$0; print "str="str
cmd="printf \"%s\" \"" str "\""; print "cmd="cmd
}'
str=foo'bar $(ls) $HOME
cmd=printf "%s" "foo'bar $(ls) $HOME"
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句