web-dev-qa-db-de.com

Entfernen Sie einen Teil des Pfads unter Unix

Ich versuche, einen Teil des Pfads in einer Zeichenfolge zu entfernen. Ich habe den Pfad:

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

Ich möchte den ersten Teil /path/to/file/drive entfernen und die Ausgabe erzeugen:

file/path/

Hinweis: Ich habe mehrere Pfade in einer while-Schleife, mit dem gleichen /path/to/file/drive in allen, aber ich suche nur nach dem "Wie", um den gewünschten String zu entfernen.

Ich habe einige Beispiele gefunden, aber ich kann sie nicht zur Arbeit bringen:

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 ist der zweite Teil des Strings und ich mache eindeutig etwas falsch ... vielleicht gibt es einen einfacheren Weg?

44
esausilva

Sie können dazu auch die POSIX-Shell-Variablenerweiterung verwenden.

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

Der #..-Teil entfernt eine führende übereinstimmende Zeichenfolge, wenn die Variable erweitert wird. Dies ist besonders nützlich, wenn Ihre Zeichenfolgen bereits in Shell-Variablen enthalten sind, z. B. wenn Sie eine for-Schleife verwenden. Sie können übereinstimmende Zeichenfolgen (z. B. eine Erweiterung) auch vom Ende einer Variablen entfernen, indem Sie %... verwenden. Siehe die Manpage bash für die blutigen Details.

42
evil otto

Wenn Sie eine bestimmte Anzahl von Pfadkomponenten entfernen möchten, sollten Sie cut mit -d'/' verwenden. Wenn zum Beispiel path=/home/dude/some/deepish/dir:

So entfernen Sie die ersten beiden Komponenten:

# (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

Um die ersten beiden Komponenten zu behalten:

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

So entfernen Sie die letzten beiden Komponenten (rev kehrt die Zeichenfolge um):

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

Um die letzten drei Komponenten zu behalten:

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

Wenn Sie alles vor einer bestimmten Komponente entfernen möchten, funktioniert sed:

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

Oder nach einer bestimmten Komponente:

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

Es ist sogar noch einfacher, wenn Sie die von Ihnen angegebene Komponente nicht beibehalten möchten:

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

Und wenn Sie konsequent sein wollen, können Sie auch den nachfolgenden Schrägstrich anpassen:

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

Wenn Sie mehrere Schrägstriche abgleichen, sollten Sie natürlich das sed-Trennzeichen umschalten:

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

Beachten Sie, dass alle diese Beispiele absolute Pfade verwenden. Sie müssen also herumspielen, damit sie mit relativen Pfaden arbeiten.

57
ACK_stoverflow

Wenn Sie den zu entfernenden Teil nicht hartcodieren möchten:

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

Eine Möglichkeit, dies mit sed zu tun, ist

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

Die Verwendung von ${path#/path/to/file/drive/}, wie von böse otto vorgeschlagen, ist sicherlich die typische/beste Möglichkeit, dies zu tun, aber da es viele Vorschläge für sed gibt, ist es wichtig, darauf hinzuweisen, dass sed zu viel ist, wenn Sie mit einer festen Saite arbeiten. Sie können auch tun:

echo $PATH | cut -b 21-

Die ersten 20 Zeichen werden verworfen. Ebenso können Sie ${PATH:20} in der bash oder $PATH[20,-1] in zsh verwenden.

4
William Pursell

Wenn Sie die ersten N Teile des Pfads entfernen möchten, können Sie natürlich N -Aufrufe für basename verwenden, wie in glenns Antwort .

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

Insbesondere bedeutet ${path#*/*/*/*/*/}"return $path minus dem kürzesten Präfix, der 5 Schrägstriche enthält".

2
Fritz

Pure Bash, ohne die Antwort hart zu programmieren

basenames()
{
  local d="${2}"
  for ((x=0; x<"${1}"; x++)); do
    d="${d%/*}"
  done
  echo "${2#"${d}"/}"
}
  • Argument 1 - Wie viele Ebenen möchten Sie behalten (2 in der ursprünglichen Frage)
  • Argument 2 - Der vollständige Pfad
0
Andy