シェル変数からパスのファイル名部分を取得する方法

シェル変数からパスのファイル名部分を取得する方法

シェル変数はパスを保持します。ファイル名部分をどのように取得できますか?

bash(1)で、私は実験を通して環境変数の名前が."${i/*\///}"どこにあるかを介して実行できることを発見しました。iこのアプローチは醜いだけでなく、/パスに文字が含まれていない場合でも間違っています。

そのような機能が必要な実際のケースを紹介します。ソースディレクトリ内の各PDFファイルに対して現在のディレクトリへのシンボリックリンクを作成するとします。

$ for i in /source/path/*.pdf; do\
  ln -s "$i" ."${i/*\///}"; \
  done

答え1

${i##*/}

bashこれは、、dashなどをksh含むPosixシェルに適用されます。zsh標準からPOSIXパラメータ拡張セクションPosixシェルとユーティリティの仕様:

${パラメータ##[単語]}
最大プレフィックスパターンを削除します。パターンを生成するには、単語を拡張する必要があります。次に、パラメータ拡張によって、プレフィックスの最大部分が削除されたパターンと一致するパラメータを生成する必要があります。

あるいは、伝統的にbasenameこの目的のためにコマンドが使用されていました。 警告する:basename外部コマンド(例:)で実装されているため、パフォーマンスが重要な問題になる可能性があります/usr/bin/basename。ループ内でこれを行うので、各ファイルに対して外部コマンドを呼び出します。 1000ファイルのリストの場合、これはbasename0.05秒(パラメータ拡張)と2.0秒(コマンド)の差になる可能性があります。ただし、10,000個のファイルリストの場合、これは0.5秒(拡張)と20秒()の差がありますbasename。ファイルの数が増えるほど、パフォーマンスの違いはより深刻になります。

読みやすさとパフォーマンスのために、次の独自の機能を実装できますbasename

mybasename() { echo "${1##*/}"; }

(完全なコマンドラインインターフェイスの機能および/またはbasename実装のためのより良い名前の選択は、読者の練習問題として残ります。)

答え2

パスを変数に入れ、その長さの数を使用して、次のようにフルパス名から必要な部分文字列のみを取得できます。

$ pth="/source/path/";
$ for i in $path*.pdf; do \
  ln -s "$i" ./"${i:${#pth}}"; \
  done

関連情報