Cut/awk の代わりに bash 変数置換を使用する

Cut/awk の代わりに bash 変数置換を使用する

bash変数置換を使用して区切り文字に基づいて変数の一部を抽出できますか?ファイル名の直接ディレクトリ名を取得しようとしています(この場合foo)。

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

私は私が次のことをすることができることを知っています。

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

または

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

awkただし、ブランチ/cut複数のファイル名は非常に遅くなります。

実際のファイルを使用して、さまざまなソリューションの分析を行いました。

エコ|カット:

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

エコ

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

@steeldriverの変数置換/シェルパラメータ拡張:

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

awk/sed/cut の代わりに "dirname" コマンドを使用するとどうなりますか?

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

生産する:

./foo/bar

関連情報