Comment diviser la variable $ 0 pour trouver le répertoire et les chemins relatifs dans bash?

10

La variable $ 0 contient les informations de chemin du script.

  • Comment puis-je changer les informations de chemin en chemin absolu? Je veux dire comment traiter ~,., .. ou similaire?
  • Comment puis-je diviser les informations de chemin en répertoire et nom de fichier?

Je pourrais utiliser python / perl pour cela, mais je veux utiliser bash si possible.

prosseek
la source
qu'essayez-vous d'accomplir? btw. appeler un script avec ~ / foo.sh étendra ~ dans mon répertoire personnel pour 0 $ avec ma version bash (GNU bash, version 4.1.5 (2) -release- (x86_64-unknown-linux-gnu))
echox

Réponses:

17

Vous n'avez pas besoin de traiter des choses comme ~, le shell le fait pour vous. C'est pourquoi vous pouvez passer ~/filenameà n'importe quel script ou programme et cela fonctionne - tous ces programmes ne se gèrent pas ~eux-mêmes, votre shell convertit l'argument /home/username/filenameet le transmet au programme à la place:

$ echo ~/filename
/home/mrozekma/filename

Si vous avez besoin d'un nom de fichier canonique (qui n'inclut pas de choses comme ..), utilisez realpath(merci Neil ):

$ realpath ~/../filename
/home/filename

Pour diviser le chemin en nom de répertoire et nom de fichier, utilisez dirnameet basename:

$ dirname /foo/bar/baz
/foo/bar

$ basename /foo/bar/baz
baz
Michael Mrozek
la source
Je pense que vous voulez dire realpath, pas readlink. readlink ne fonctionnera pas dans la situation courante, c'est-à-dire lorsque le lien utilise un chemin relatif et que vous n'êtes pas dans le même répertoire que le lien.
Neil Mayhew
@Neil realpathest mieux, mais readlinksemble fonctionner quand je l'essaye; connaissez-vous un exemple où il échoue?
Michael Mrozek
1
cd /tmp; touch foo; ln -s foo bar; cd; readlink /tmp/bar. Cela revient fooet realpathrevient /tmp/foo, ce que vous voulez.
Neil Mayhew
1
@Neil, @Michael: readlink -f(note -f) est presque équivalent à realpath, et il est plus portable: readlink -fdans GNU coreutils et existe également sur quelques autres systèmes; realpathest empaqueté séparément et ne peut pas être installé (par exemple, seuls 5 paquets non communs en dépendent dans Ubuntu 10.04 ou Debian Lenny).
Gilles 'SO- arrête d'être méchant'
@Gilles: bon point. Merci pour le rappel sur realpath -f.
Neil Mayhew du
5

Utiliser dirname et basename comme mentionné par Michael devrait être le moyen le plus sûr d'obtenir ce que vous voulez.

Quoi qu'il en soit, si vous voulez vraiment le faire avec des "outils bash uniquement", vous pouvez utiliser la substitution de paramètres:

echo `basename $PWD`        # Basename of current working directory.
echo "${PWD##*/}"           # Basename of current working directory.
echo
echo `basename $0`          # Name of script.
echo $0                     # Name of script.
echo "${0##*/}"             # Name of script.
echo
filename=test.data
echo "${filename##*.}"      # data
                            # Extension of filename.

Cet exemple est directement tiré du Guide de script Bash avancé qui vaut le détour.

L'explication est assez simple:

$ {var # Pattern} Supprimez de $ var la partie la plus courte de $ Pattern qui correspond à l'extrémité avant de $ var. $ {var ## Pattern} Supprimez de $ var la partie la plus longue de $ Pattern qui correspond à l'extrémité avant de $ var.

Regardez le modèle comme une expression régulière et le #ou ##comme une sorte de modificateur gourmand / non gourmand.

Cela peut devenir utile si vous devez effectuer des extractions plus compliquées d'une partie de chemins.

écho
la source
5
Méfiez-vous lors de l'utilisation ${...##...}et des amis plutôt que dirnameet basenamequ'ils ne fonctionnent pas dans tous les cas. Par exemple, les deux ${0##*/}et ${0%/*}développez la même chose que $0si $0ne contient pas de /.
Gilles 'SO- arrête d'être méchant'
@Gilles Je comprends pourquoi ce ${0%/*}n'est pas une bonne alternative à dirname. Cependant, quel est le problème avec l'utilisation ${0##*/}au lieu de basename?
toxalot
@toxalot Pour celui-ci, le seul problème est quand $0est un nom de répertoire avec une fin /. Mais je regrette mes conseils, car dirnamene fait pas mieux.
Gilles 'SO- arrête d'être méchant'
2

realpath est une commande qui vous indique le vrai chemin (supprime .. et les liens symboliques etc.)

Il est standard avec FreeBSD. Selon cette discussion, il est également disponible pour Linux:

http://www.unix.com/shell-programming-scripting/89294-geting-real-path.html

Cette discussion offre également une solution bash:

$ bash -c "cd /foo/../bar/ ; pwd"

la source
1
Exactement, quelque chose comme ça fonctionne généralement: MYDIR = "$ (cd $ (dirname" $ ​​0 "); pwd)"
Kevin Cantu le