web-dev-qa-db-fra.com

Supprimer une partie du chemin sous Unix

J'essaie de supprimer une partie du chemin dans une chaîne. J'ai le chemin:

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

Je veux supprimer la première partie /path/to/file/drive et produire le résultat:

file/path/

Remarque: j'ai plusieurs chemins dans une boucle while, avec le même /path/to/file/drive dans chacun d'eux, mais je cherche simplement le "comment faire" pour supprimer la chaîne souhaitée.

J'ai trouvé des exemples, mais je ne peux pas les faire fonctionner:

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 étant la deuxième partie de la chaîne et je suis clairement en train de faire quelque chose de mal ... peut-être qu'il existe un moyen plus facile?

44
esausilva

Vous pouvez également utiliser le développement de variables POSIX Shell pour ce faire.

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

La partie #.. supprime une chaîne de correspondance en tête lorsque la variable est développée; Ceci est particulièrement utile si vos chaînes sont déjà dans des variables Shell, comme si vous utilisiez une boucle for. Vous pouvez également supprimer les chaînes correspondantes (par exemple, une extension) de la fin d'une variable, à l'aide de %.... Voir la page de manuel bash pour les détails sanglants.

42
evil otto

Si vous souhaitez supprimer un certain NOMBRE de composants de chemin, vous devez utiliser cut avec -d'/'. Par exemple, si path=/home/dude/some/deepish/dir:

Pour supprimer les deux premiers composants:

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

Pour conserver les deux premiers composants:

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

Pour supprimer les deux derniers composants (rev inverse la chaîne):

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

Pour conserver les trois derniers composants:

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

Ou, si vous souhaitez tout supprimer avant un composant particulier, sed fonctionnerait:

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

Ou après un composant particulier:

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

C'est encore plus facile si vous ne souhaitez pas conserver le composant que vous spécifiez:

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

Et si vous voulez être cohérent, vous pouvez également faire correspondre la barre oblique suivante:

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

Bien sûr, si vous faites correspondre plusieurs barres obliques, vous devez changer le délimiteur sed:

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

Notez que ces exemples utilisent tous des chemins absolus, vous devrez jouer pour les faire fonctionner avec des chemins relatifs.

57
ACK_stoverflow

Si vous ne voulez pas coder en dur la partie que vous supprimez:

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

Une façon de faire cela avec sed est

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

Utiliser ${path#/path/to/file/drive/} comme suggéré par evil otto est certainement la meilleure façon de le faire, mais comme il existe de nombreuses suggestions de sed, il est intéressant de souligner que sed est excessif si vous travaillez avec une chaîne fixe. Vous pouvez aussi faire:

echo $PATH | cut -b 21-

Pour supprimer les 20 premiers caractères. De même, vous pouvez utiliser ${PATH:20} dans bash ou $PATH[20,-1] dans zsh.

4
William Pursell

Si vous voulez supprimer les N premières parties du chemin, vous pouvez bien sûr utiliser les appels N à basename, comme dans la réponse de glenn , mais il est probablement plus facile d'utiliser un déplacement:

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

Plus précisément, ${path#*/*/*/*/*/} signifie "return $path moins le préfixe le plus court contenant 5 barres obliques".

2
Fritz

Pure bash, sans coder en dur la réponse

basenames()
{
  local d="${2}"
  for ((x=0; x<"${1}"; x++)); do
    d="${d%/*}"
  done
  echo "${2#"${d}"/}"
}
  • Argument 1 - Combien de niveaux voulez-vous conserver (2 dans la question initiale)
  • Argument 2 - Le chemin complet
0
Andy