我有一个短外壳函数,可以将人类可读的字节单位转换为字节整数,因此,例如,
10m 至 10000000 4KB 到 4000 1KiB 至 1024 2Gib 至 2147483648
这是代码:
dehumanise() {
for v in "$@"
do
echo $v | awk
'BEGIN{IGNORECASE = 1}
function printpower(n,b,p) {printf "%un", n*b^p; next}
/[0-9]$/{print $1;next};
/K(B)?$/{ printpower($1, 10, 3)};
/M(B)?$/{ printpower($1, 10, 6)};
/G(B)?$/{ printpower($1, 10, 9)};
/T(B)?$/{ printpower($1, 10, 12)};
/Ki(B)?$/{printpower($1, 2, 10)};
/Mi(B)?$/{printpower($1, 2, 20)};
/Gi(B)?$/{printpower($1, 2, 30)};
/Ti(B)?$/{printpower($1, 2, 40)}'
done
}
我也在互联网上的某个地方找到了代码,我对 awk 不太有信心。该功能运行良好,直到几天前我重新安装了MacBook。现在它抛出一个错误
awk:在函数打印功率中源代码行 2 的函数内,下一个是非法的 上下文是 function printpower(n,b,p) {printf "%u", n*b^p;>>>next} <<<</p>
据我了解,next 在 awk 中使用直接结束记录。因此,在这种情况下,它将结束 awk 语句,因为它只有一个输入。
我试图将下一条语句简单地移到打印电源(...下一个。 但这会导致函数根本不提供任何输出。
有人可以帮我修复尴尬的陈述吗?
# awk --version
awk 版本20121220
macOS awk 版本
解决
没有输出的事情可能是macOS awk版本的问题。我安装并用gawk替换了它:
brew install gawk
brew link --overwrite gawk
现在它在没有下一个语句的情况下工作正常。
软件设计基础 - 避免控制反转。在这种情况下,您不希望某些下属功能突然负责您的整个处理控制流程,而 IT决定"搞砸你们,我决定跳到下一条记录"。所以是的,不要把next
放在函数中!话虽如此,POSIX 并没有说你不能在函数中使用 next,但它也没有明确说你可以,所以一些 awk 实现(显然你正在使用的那个)决定禁止它,而 gawk 和其他一些 awk 允许它。
你的脚本中也有特定于 gawk 的代码(IGNORECASE
),所以它无论如何都只能与 gawk 一起使用。
以下是真正编写脚本以在任何 awk 中工作的方法:
awk '
{ $0=tolower($0); b=p=0 }
/[0-9]$/ { b = 1; p = 1 }
/kb?$/ { b = 10; p = 3 }
/mb?$/ { b = 10; p = 6 }
/gb?$/ { b = 10; p = 9 }
/tb?$/ { b = 10; p = 12 }
/kib$/ { b = 2; p = 10 }
/mib$/ { b = 2; p = 20 }
/gib$/ { b = 2; p = 30 }
/tib$/ { b = 2; p = 40 }
p { printf "%un", $2*b^p }
'
如果您愿意,您可以在主体中的每个p
分配后添加; next
,但这不会影响输出,只需提高效率,如果您的输入长达数千行,这将很重要。
正如消息所说,您不能在函数中使用next
。您必须在每次函数调用后放置它:
/KB?$/ { printpower($1, 10, 3); next; }
/MB?$/ { printpower($1, 10, 6); next; }
...
但是,如果您不介意额外的 CPU 周期,您可以让awk
测试剩余的模式(任何地方都没有next
)。请注意,B
周围的括号是多余的,我已经删除了它们。
$ dehumanise 1000MiB 19Ki
1048576000
19456
您可以在函数中使用控制变量并检查变量的值以决定在主例程中使用下一个。
# MAIN
{
myfunction(test)
if (result == 1) next
# result is not 1, just continue
# more statements
}
function myfunction(a) {
# default result is 0
result = 0
# some test
if ($1 ~ /searchterm/) {
result = 1
}
}