84

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

/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番目の部分であり、私は明らかに何か間違ったことをしています...多分もっと簡単な方法がありますか?

4

8 に答える 8

116

特定の数のパスコンポーネントを削除する場合は、を使用cutする必要があります-d'/'。たとえば、次の場合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-
# output:
# some/deepish/dir

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

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

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

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

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

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

または、特定のコンポーネントの前にすべてを削除したい場合は、次のように機能しますsed

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

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

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

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

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

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

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

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

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

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

于 2015-07-30T15:59:20.957 に答える
82

これを行うには、POSIXシェル変数展開を使用することもできます。

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

#..変数が展開されると、パーツは先頭の一致する文字列を取り除きます。forこれは、ループを使用している場合など、文字列がすでにシェル変数に含まれている場合に特に便利です。を使用して、変数の末尾から一致する文字列(たとえば、拡張子)を削除することもできます%...。厄介な詳細については、bashmanページを参照してください。

于 2012-06-11T20:23:07.007 に答える
32

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

$ s='/path/to/file/drive/file/path/'
$ echo ${s#$(dirname "$(dirname "$s")")/}
file/path/
于 2012-06-11T22:28:59.927 に答える
12

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

echo /path/to/file/drive/file/path/ | sed 's:^/path/to/file/drive/::'
于 2012-06-11T20:08:50.270 に答える
5

パスの最初のN個の部分を削除する場合は、もちろんglennの回答のようにN個の呼び出しを使用できますが、グロブを使用する方がおそらく簡単です。dirname

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

具体的に${path#*/*/*/*/*/}は、 「リターン$pathから5つのスラッシュを含む最短のプレフィックスを引いたもの」を意味します。

于 2014-08-14T14:52:01.417 に答える
4

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

echo $PATH | cut -b 21-

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

于 2012-06-13T20:32:20.473 に答える
1

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

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

vsi_common元のバージョン)から取得

于 2018-04-10T16:04:28.090 に答える
0

これは、変数に対応し(フルパスをハードコーディングしたくない場合)、stdinをにパイプする必要をなくし、ループsedを含む単純なbash構文を使用したソリューションです。for

FULLPATH="/path/to/file/drive/file/path/"
SUBPATH="/path/to/file/drive/"
for i in $FULLPATH;
do
echo ${i#$SUBPATH}
done

@evil ottoが前述したように#、このシナリオではプレフィックスを削除するために記号が使用されます。

于 2021-06-03T20:39:50.057 に答える