web-dev-qa-db-ja.com

Unixでパスの一部を削除する

文字列内のパスの一部を削除しようとしています。私にはパスがあります:

/path/to/file/drive/file/path/

最初の部分/path/to/file/driveを削除して、出力を生成します。

file/path/

注:whileループには、同じ/path/to/file/driveがすべて含まれる複数のパスがありますが、目的の文字列を削除するための「方法」を探しています。

いくつかの例を見つけましたが、それらを動作させることはできません。

echo /path/to/file/drive/file/path/ | sed 's:/path/to/file/drive:\2:'
echo /path/to/file/drive/file/path/ | sed 's:/path/to/file/drive:2'

\2は文字列の2番目の部分であり、明らかに間違ったことをしている...おそらくもっと簡単な方法がありますか?

54
esausilva

POSIXシェル変数展開を使用してこれを行うこともできます。

path=/path/to/file/drive/file/path/
echo ${path#/path/to/file/drive/}

#..部分は、変数が展開されるときに先頭の一致する文字列を取り除きます。これは、forループを使用している場合など、文字列が既にシェル変数にある場合に特に便利です。 %...を使用して、変数の末尾から一致する文字列(拡張子など)を取り除くこともできます。面倒な詳細については、bash manページを参照してください。

46
evil otto

特定の数のパスコンポーネントを削除する場合は、-d'/'cutを使用する必要があります。たとえば、path=/home/dude/some/deepish/dirの場合:

最初の2つのコンポーネントを削除するには:

# (Add 2 to the number of components to remove to get the value to pass to -f)
$ echo $path | cut -d'/' -f4-
some/deepish/dir

最初の2つのコンポーネントを保持するには:

$ echo $path | cut -d'/' -f-3
/home/dude

最後の2つのコンポーネントを削除するには(revは文字列を逆にします):

$ echo $path | rev | cut -d'/' -f4- | rev
/home/dude/some

最後の3つのコンポーネントを保持するには:

$ echo $path | rev | cut -d'/' -f-3 | rev
some/deepish/dir

または、特定のコンポーネントの前のすべてを削除する場合は、sedが機能します。

$ echo $path | sed 's/.*\(some\)/\1/g'
some/deepish/dir

または、特定のコンポーネントの後:

$ echo $path | sed 's/\(dude\).*/\1/g'
/home/dude

指定するコンポーネントを保持したくない場合は、さらに簡単です。

$ echo $path | sed 's/some.*//g'
/home/dude/

一貫性を保ちたい場合は、末尾のスラッシュも一致させることができます。

$ echo $path | sed 's/\/some.*//g'
/home/dude

もちろん、複数のスラッシュを一致させる場合は、sed区切り文字を切り替える必要があります。

$ echo $path | sed 's!/some.*!!g'
/home/dude

これらの例はすべて絶対パスを使用していることに注意してください。相対パスで動作させるには、いじってみる必要があります。

67
ACK_stoverflow

削除する部分をハードコーディングしたくない場合:

$ s='/path/to/file/drive/file/path/'
$ echo ${s#$(dirname "$(dirname "$s")")/}
file/path/
24
glenn jackman

Sedでこれを行う1つの方法は

echo /path/to/file/drive/file/path/ | sed 's:^/path/to/file/drive/::'
9
Jonathan Callen

邪悪なオットーによって示唆された${path#/path/to/file/drive/}を使用することは確かにこれを行うための典型的/最良の方法ですが、sedの提案が多数あるため、固定文字列を使用している場合はsedが過剰であることを指摘する価値があります。次のこともできます。

echo $PATH | cut -b 21-

最初の20文字を破棄します。同様に、bashで${PATH:20}またはzshで$PATH[20,-1]を使用できます。

4
William Pursell

パスの最初のN部分を削除する場合は、もちろん[〜#〜] n [〜#〜]を呼び出してdirnameを呼び出します glenn's answer のように、グロブを使用する方がおそらく簡単です:

path=/path/to/file/drive/file/path/
echo "${path#*/*/*/*/*/}"   #  file/path/

具体的には、${path#*/*/*/*/*/}"return $pathマイナス5つのスラッシュを含む最短プレフィックス "

4
Fritz

答えをハードコーディングせずに純粋なbash

basenames()
{
  local d="${2}"
  for ((x=0; x<"${1}"; x++)); do
    d="${d%/*}"
  done
  echo "${2#"${d}"/}"
}
  • 引数1-保持するレベルの数(元の質問の2)
  • 引数2-フルパス
0
Andy