我经常使用awk
来选择单列,在了解了别名之后我开始使用
alias a1='awk '\{print $1}'\'
alias a2='awk '\{print $2}'\'
...
在我学到更多东西后,我认为那些是俗气的,并用
代替function a() {
awk "{print \$$1}"
}
现在我可以执行a 3
或a 11
而无需创建显式别名。
这样很好,但有时我需要选择多个列,当我这样做时,我不得不求助于输入实际的完整awk '{print ...}'
命令(恐怖!)。
所以我试图找到一种类似于a
函数的方法,但是会接受不同数量的参数,所以我可以做a 3
或{{ 1}}或a 5 7
。
我已尝试使用a 2 4 9
和$@
进行不同尝试,但无法正确使用我现在尝试的所有内容,我知道这些都是俗气的解决方法,所以我&# 39;而宁愿停下来问问如何以正确的方式去做。
谢谢大家。
答案 0 :(得分:3)
你可能会因为这种事情而变得任意复杂(如果你想像a 2-5 7 11-
一样想说cut
怎么办?)但是这里有一个可以使用数字列表:
a() { (IFS=,; awk '{print '"${*/#/$}"'}'); }
这需要一些解释。
a() { ... }
定义了一个shell function,它以各种方式与别名不同,其中一个就是你可以给它参数。
在shell函数中,我想更改IFS
的值;为了避免记住旧值并将其更改回来,我将实际上想要用(...)
执行的命令包围起来,这使得它在子shell中执行。当子shell完成后,所有环境变化都会随之完成,因此它有效地将更改变为IFS
本地。
IFS
是用于word splitting的字符集,但它还定义了用于分隔"$*"
扩展中元素的字符(即函数或脚本列表)当它被引号包围时。因此,将其设置为,
表示$*
展开将是以逗号分隔的列表。
我想要创建的awk程序实际上类似于{print $1,$4,$7}
,所以除了在列表之间添加逗号之外,我需要在每个数字之前添加$
。我使用bash
parameter expansion替代语法执行此操作:${parameter/pattern/replacement}
。通过将*
指定为参数,我得到$*
,并将替换应用于每个参数。 (请注意,扩展是引用的。如果不是,它将无法工作。)
在替换表达式中,模式为空,因为模式开头的#
字符表示匹配必须位于字符串的开头。由于实际模式为空,因此第一个匹配始终位于字符串的开头,因此将在每个参数的开头插入替换($
)。需要#
,因为//
在语法上是不同的:它意味着"更改所有出现的模式"而不仅仅是第一个。
与许多语言不同,bash搜索和替换表达式不是以/
结尾,而是以匹配的}
结尾。如果您输入${p/foo/bar/}
,则会将foo
的第一个实例替换为bar/
。
答案 1 :(得分:3)
$ cat tst.sh
function a {
awk -v args="$*" '
BEGIN { n=split(args,f) }
{ for (i=1;i<=n;i++) printf "%s%s", $(f[i]), (i<n?OFS:ORS) }
'
}
echo "a b c d e f" | a 1 3 5
echo "---"
echo "a b c d e f" | a 1 3 4 6
$ ./tst.sh
a c e
---
a c d f