堅牢なパスの構築


16

シェルスクリプト(zshなど)にいくつかの変数があるとします。

FOLDER_1, FOLDER_2, etc.

これらの変数は、から派生するフォルダーを参照します/。たとえば、パスがある場合/home/me/stuff/items

変数は次のとおりです。

FOLDER_1='home'
FOLDER_2='me'
FOLDER_3='stuff'

ここで、変数を連結して対応するパスを構築し直したいとします。可能な方法の1つは、次のようにパスを作成することです。

PATH=$FOLDER_1/$FOLDER_2/$FOLDER_3/

ただし、変数の中にはFOLDER_iスラッシュが付いているものもあれば、付いていないものもあると言う(そして、どれがわからないのか)

FOLDER_1='home'
FOLDER_2='stuff/'
FOLDER_3='items'

私の質問は次のとおりです。どうすればパスを堅牢に構築できますか?(たとえば、二重スラッシュを避け、必要な場所に追加します)。

これを行う1つの方法は/、変数のペア間に常に追加し、で重複を削除することsedだと思いましたが、それを動作させることはできません(私はで/正しく処理しているかわかりませんsed)。

また、私は車輪を再発明していますか?(つまり、すでにこれを行う組み込み機能はありますか?)。

最後に、変数が配列内にある場合、たとえばFOLDERS、ループせずにこれを行うことは可能ですか?(または、ループFOLDERS内にあるが、配列内にいくつあるかを知らずに)。

回答:


12

printf配列で使用できます:

parts=("$FOLDER_1" "$FOLDER_2" "$FOLDER_3");
printf '/%s' "${parts[@]%/}"
# Use "printf -v path" to save it into a variable called "path" instead of printing it

%オペレータは、この場合には、末尾の文字列をトリミング/。に適用することによりparts[@]、各配列メンバーを個別にトリミングします。

このprintfトリックを理解する鍵は、man 1 printf「引数を満たすためにフォーマット文字列が必要に応じて何度でも再利用される」ということです。


単一の%方法は、クエストで言及された単一の末尾のスラッシュに対して機能します。複数のスラッシュがある場合に対応するために${parts[@]%%/*}動作します。ここではスラッシュ問題についてもう少し情報へのリンクです:ダブルスラッシュは、UNIXパスで何を意味するのですか?'cd dir / subdir //は有効です
Peter.O

2
@fered:/*このケースではないではない、ゼロ平均以上のスラッシュではなく、任意の数の文字が続くスラッシュを。つまり、パスがスラッシュで始まる場合、結果は空の文字列になります!
l0b0

例のように、末尾のスラッシュしかないと考えていました。しかし、先頭のスラッシュ(ES)の可能性に適応するためには、bashのextglob使用..により、(正規表現とする)ことができるshopt -s extglob; ${parts[@]%%/+(/)}...
Peter.O

15

簡単な答えは、心配するのをやめて、複数のスラッシュを愛することです。複数のスラッシュは、単一のスラッシュと同じ効果があります//いくつかのシステムで始まるパスの意味が異なることを除いて、Windows上のUNIXエミュレーションレイヤーのみが名前を付けることができます)。それは設計によるものであり、複数のスラッシュを心配することなくファイル名をアセンブルできることは、その設計決定の主要な部分でした。

配列要素を結合するには、zshでj パラメーター展開フラグを使用できます。

dir=${(j:/:)FOLDERS}

重複しているスラッシュを押しつぶすことはできますが、それは単なる見た目です。

setopt extended_glob
dir=${${(j:/:)FOLDERS}//\/\/##/\/}

kshとbashでは、の最初の文字を$IFSセパレータとして使用して配列を結合できます。その後、重複するスラッシュをつぶすことができます。bashでは、shopt -s extglob以下のスニペットの最後の行でkshグロブを有効にする必要があります。

IFS=/
dir="${FOLDERS[*]}"
unset IFS
dir=${dir//\/+(\/)//}

3

どうしてsedうまくいかないの?sed 's|/\+|/|g'連結した後、またはそのsed 's|/||g'前に試してください。


1

bash 4拡張グロビングを導入しました。これにより、パラメータ置換で正規表現のマッチングが可能になります${var....}...デフォルトではオフになっています。スクリプトで有効にするには、単にシェルオプションextglobを設定します...

$ dir == と仮定する/home/me/////////stuff//items

shopt -s extglob; dir="${dir//+(\/)//}"

結果の$ dirの

/home/me/stuff/items  

以下に、do-sおよび-don't -sの例を示します-Bash Extended Globbing

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.