使用 bash 变量替换代替 cut/awk

使用 bash 变量替换代替 cut/awk

我可以使用 bash 变量替换来根据定界符提取变量的一部分吗?我试图获取文件名的直接目录名(在本例中为foo)。

$ filename=./foo/bar/baz.xml

我知道我可以做类似的事情

echo $filename | cut -d '/' -f 2

或者

echo $filename | awk -F '/' '{print $2}'

awk但是 fork /cut多个文件名的速度变得很慢。

我使用我的真实文件对各种解决方案进行了一些分析:

回声|剪切:

real    2m56.805s
user    0m37.009s
sys     1m26.067s

回声| awk:

real    2m56.282s
user    0m38.157s
sys     1m31.016s

@steeldriver的变量替换/shell参数扩展:

real    0m0.660s
user    0m0.421s
sys     0m0.235s

@jai_s 的 IFS 争论:

real    1m26.243s
user    0m13.751s
sys     0m28.969s

这两个建议都比我现有的想法有了巨大的改进,但变量替换是最快的,因为它不需要分叉任何新的流程。

答案1

您可以删除匹配的最短前导子字符串*/

tmp="${filename#*/}"

然后删除匹配的最长尾随子字符串/*

echo "${tmp%%/*}"

答案2

    echo $f
    a/b/c

    $ (IFS='/';set $f; echo $1)
     a

    $ (IFS='/';set $f; echo $2)
     b

    $ (IFS='/';set $f; echo $3)
     c

使用通配符,它​​似乎可以使用双引号或单引号 -

    f="a?b?c"
     $(IFS="?"; set $f; echo $1)
     a
    echo $f
    a*b*c
    (IFS="*"; set $f; echo $1)
    a

是的,您必须将 IFS 恢复为默认值

    unset IFS

答案3

将列表提供给以awk加快速度:

awk -F '/' '{print $2}' < <(find /usr)
awk -F '/' '{print $2}' < inputfile

示范:

time awk -F '/' '{print $2; SUM++} END {print "number of directories found: " SUM}' < <(find /usr -type d)
usr
usr
.
.
number of directories found: 16748

real    0m8.910s
user    0m0.050s
sys     0m0.050s

答案4

为什么不使用“dirname”命令,而不是所有这些 awk/sed/cut 东西?

filename=./foo/bar/baz.xml
dirname $filename

产量:

./foo/bar

相关内容