Ou plus généralement, comment supprimer un élément d'une liste séparée par deux-points dans une variable d'environnement Bash?
Je pensais avoir vu un moyen simple de le faire il y a des années, en utilisant les formes plus avancées d'expansion variable de Bash, mais si c'est le cas, j'en ai perdu la trace. Une recherche rapide sur Google a produit étonnamment peu de résultats pertinents et aucun que j'appellerais «simple» ou «élégant». Par exemple, deux méthodes utilisant respectivement sed et awk:
PATH=$(echo $PATH | sed -e 's;:\?/home/user/bin;;' -e 's;/home/user/bin:\?;;')
PATH=!(awk -F: '{for(i=1;i<=NF;i++){if(!($i in a)){a[$i];printf s$i;s=":"}}}'<<<$PATH)
N'existe-t-il rien de simple? Y a-t-il quelque chose d'analogue à une fonction split () dans Bash?
Mise à jour:
il semble que je doive m'excuser pour ma question intentionnellement vague; J'étais moins intéressé à résoudre un cas d'utilisation spécifique qu'à provoquer une bonne discussion. Heureusement, je l'ai!
Il existe ici des techniques très intelligentes. En fin de compte, j'ai ajouté les trois fonctions suivantes à ma boîte à outils. La magie opère dans path_remove, qui repose en grande partie sur l'utilisation intelligente par Martin York de la awk
variable RS de 's.
path_append () { path_remove $1; export PATH="$PATH:$1"; }
path_prepend () { path_remove $1; export PATH="$1:$PATH"; }
path_remove () { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`; }
Le seul vrai problème ici est l'utilisation de sed
pour supprimer les deux points de fin. Compte tenu de la simplicité du reste de la solution de Martin, je suis tout à fait disposé à vivre avec!
Question connexe: Comment manipuler les éléments $ PATH dans les scripts shell?
la source
WORK=`echo -n ${1} | awk -v RS=: -v ORS=: '$0 != "'${3}'"' | sed 's/:$//'`; eval "export ${2}=${WORK}"
mais vous devez l'appeler commefunc $VAR VAR pattern
(basé sur @ martin-york et @ andrew-aylett)Réponses:
Une minute avec awk:
Edit: Il répond aux commentaires ci-dessous:
Modifier en réponse à un problème de sécurité: (qui n'est pas pertinent pour la question)
Cela supprime tous les deux-points de fin en supprimant les dernières entrées, ce qui ajouterait effectivement
.
à votre chemin.la source
PATH
variable indique , comme règle spéciale, le répertoire courant dans tous les shells Unix depuis au moins V7 Unix de 1979. C'est toujours le casbash
. Consultez le manuel ou essayez par vous-même.Mon sale hack:
la source
Étant donné que le gros problème de la substitution concerne les cas finaux, pourquoi ne pas différencier les cas finaux des autres cas? Si le chemin avait déjà des deux-points au début et à la fin, nous pourrions simplement rechercher la chaîne souhaitée entourée de deux points. Dans l'état actuel des choses, nous pouvons facilement ajouter ces deux points et les supprimer par la suite.
Pure bash :).
la source
WORK
etPATH
que l'expansion des variables se produit après que la ligne est analysée en sections pour l'affectation de variables et l'exécution de commandes.REMOVE
peut avoir besoin d'être cité, ou vous pouvez simplement mettre votre chaîne directement dans le remplacement s'il s'agit d'une constante.Voici la solution la plus simple que je puisse concevoir:
L'exemple ci-dessus supprimera tout élément de $ PATH contenant "usr". Vous pouvez remplacer "* usr *" par "/ home / user / bin" pour supprimer uniquement cet élément.
mise à jour par sschuberth
Même si je pense que les espaces dans un
$PATH
sont une idée horrible , voici une solution qui le gère:ou
la source
Voici une ligne unique qui, malgré les réponses actuellement acceptées et les mieux notées , n'ajoute pas de caractères invisibles à PATH et peut gérer les chemins contenant des espaces:
Personnellement, je trouve également cela facile à lire / à comprendre, et cela n'implique que des commandes courantes au lieu d'utiliser awk.
la source
export PATH=$(p=$(echo $PATH | tr ":" "\0" | grep -v -z "/cygwin/" | tr "\0" ":"); echo ${p%:})
(bien que sans doute, vous voudrez peut-être vous demander pourquoi vous en avez besoin, si vous le faites :))grep -v "^/path/to/remove\$"
ougrep -v -x "/path/to/remove"
tr
c'est plus commun queawk
? ;)tr
un interprète commeawk
.echo "..."
parprintf "%s" "..."
pour qu'il fonctionne sur des chemins similaires-e
et similaires. Voir stackoverflow.com/a/49418406/102441Voici une solution qui:
IFS
,supprime toutes les occurrences de l'argument dans
PATH
.la source
Extrayez-le de mon fichier .bashrc. Lorsque vous jouez avec PATH et qu'il se perd, awk / sed / grep devient indisponible :-)
la source
La meilleure option pure bash que j'ai trouvée jusqu'à présent est la suivante:
Ceci est basé sur la réponse pas tout à fait correcte à Ajouter un répertoire à $ PATH s'il n'est pas déjà là sur Superuser.
la source
removePath () { PATH=${PATH/":$1"/}; PATH=${PATH/"$1:"/}; }
$PATH
contient un sous-dossier du chemin cible (c'est-à-dire à supprimer). Par exemple:a:abc/def/bin:b
->a/bin:b
, quandabc/def
doit être supprimé.Je viens d'utiliser les fonctions de la distribution bash, qui existent apparemment depuis 1991. Celles-ci sont toujours dans le paquet bash-docs sur Fedora, et étaient utilisées dans
/etc/profile
, mais pas plus ...la source
J'ai écrit une réponse à cela ici (en utilisant aussi awk). Mais je ne suis pas sûr que ce soit ce que vous recherchez? Il me semble au moins clair ce qu'il fait, au lieu d'essayer de rentrer dans une seule ligne. Pour une simple doublure, cependant, qui ne supprime que des choses, je recommande
Le remplacement est
ou (plus court mais moins lisible)
Quoi qu'il en soit, pour la même question, et un tas de réponses utiles, voir ici .
la source
awk '$0 !~ "/bin"'
. C'est-à-dire conserver les lignes qui ne contiennent pas '/ bin' avec l'opérateur awk!~
.Eh bien, dans bash, comme il prend en charge les expressions régulières, je ferais simplement:
la source
J'aime les trois fonctions présentées dans la mise à jour de @ BenBlank à sa question d'origine. Pour les généraliser, j'utilise un formulaire à 2 arguments, qui me permet de définir PATH ou toute autre variable d'environnement que je souhaite:
Exemples d'utilisation:
Notez que j'ai également ajouté des guillemets pour permettre le bon traitement des chemins d'accès contenant des espaces.
la source
Quoi de plus élégant que awk?
Python! C'est une solution plus lisible et maintenable, et il est facile d'inspecter pour voir qu'elle fait vraiment ce que vous voulez.
Voulez-vous supprimer le premier élément de chemin?
(Au lieu de la tuyauterie de
echo
,os.getenv['PATH']
serait un peu plus court et fournirait le même résultat que ci-dessus, mais je crains que Python puisse faire quelque chose avec cette variable d'environnement, il est donc probablement préférable de le canaliser directement depuis l'environnement qui vous tient à cœur. .)De même pour supprimer de la fin:
Pour rendre ces fonctions shell réutilisables que vous pouvez, par exemple, coller dans votre fichier .bashrc:
la source
Oui, mettre un deux-points à la fin de PATH, par exemple, rend la suppression d'un chemin un peu moins maladroite et sujette aux erreurs.
la source
Si vous êtes préoccupé par la suppression des doublons dans $ PATH, le moyen le plus élégant, à mon humble avis, serait de ne pas les ajouter en premier lieu. En 1 ligne:
Le dossier $ peut être remplacé par n'importe quoi et peut contenir des espaces ("/ home / user / my documents")
la source
La solution pure bash la plus élégante que j'ai trouvée à ce jour:
la source
La plupart des autres solutions proposées reposent uniquement sur la correspondance de chaîne et ne prennent pas en compte les segments de chemin contenant des noms spéciaux comme
.
,..
ou~
. La fonction bash ci-dessous résout les chaînes de répertoire dans son argument et dans les segments de chemin pour trouver des correspondances de répertoire logique ainsi que des correspondances de chaîne.Tester:
la source
Linux from Scratch définit trois fonctions Bash dans
/etc/profile
:Réf: http://www.linuxfromscratch.org/blfs/view/svn/postlfs/profile.html
la source
Je sais que cette question concerne BASH, ce que tout le monde devrait préférer, mais comme j'aime la symétrie et que parfois je suis obligé d'utiliser "csh", j'ai construit l'équivalent de "path_prepend ()", "path_append ()" et "path_remove () "solution élégante ci-dessus.
L'essentiel est que "csh" n'a pas de fonctions, donc j'ai mis de petits scripts shell dans mon répertoire bin personnel qui agissent comme les fonctions. Je crée des alias pour SOURCE ces scripts pour apporter les modifications de variable d'environnement désignées.
~ / bin / _path_remove.csh:
~ / bin / _path_append.csh:
~ / bin / _path_prepend.csh:
~ / bin / .cshrc:
Vous pouvez les utiliser comme ça ...
la source
Étant donné que cela a tendance à être assez problématique, car il n'y a AUCUN moyen élégant, je recommande d'éviter le problème en réorganisant la solution: augmentez votre PATH plutôt que d'essayer de le démolir.
Je pourrais être plus précis si je connaissais votre véritable problème. En attendant, j'utiliserai une version logicielle comme contexte.
Un problème courant avec les versions logicielles est qu'il se brise sur certaines machines, en fin de compte en raison de la façon dont quelqu'un a configuré son shell par défaut (PATH et autres variables d'environnement). La solution élégante est de rendre vos scripts de construction immunisés en spécifiant entièrement l'environnement shell. Codez vos scripts de construction pour définir le PATH et d'autres variables d'environnement en fonction des éléments d'assemblage que vous contrôlez, tels que l'emplacement du compilateur, des bibliothèques, des outils, des composants, etc. Faites de chaque élément configurable quelque chose que vous pouvez définir, vérifier et puis utilisez de manière appropriée dans votre script.
Par exemple, j'ai une version Java ciblée WebLogic basée sur Maven dont j'ai hérité chez mon nouvel employeur. Le script de construction est connu pour être fragile, et un autre nouvel employé et moi avons passé trois semaines (pas à plein temps, juste ici et là, mais encore de nombreuses heures) à le faire fonctionner sur nos machines. Une étape essentielle a été de prendre le contrôle du PATH afin de savoir exactement quel Java, quel Maven et quel WebLogic était appelé. J'ai créé des variables d'environnement pour pointer vers chacun de ces outils, puis j'ai calculé le PATH en fonction de ceux-ci et de quelques autres. Des techniques similaires ont apprivoisé les autres paramètres configurables, jusqu'à ce que nous ayons finalement créé une version reproductible.
Au fait, n'utilisez pas Maven, Java est correct, et n'achetez WebLogic que si vous avez absolument besoin de son clustering (mais sinon non, et surtout pas de ses fonctionnalités propriétaires).
Meilleurs vœux.
la source
PATH
. Bien sûr, vous pouvez créer vous-même, mais chaque fois que votre administrateur déplace quelque chose, vous devez déterminer où il l'a mis. Cela va à l'encontre de l'objectif d'avoir un administrateur.Comme avec @litb, j'ai répondu à la question " Comment manipuler les éléments $ PATH dans les scripts shell ", donc ma réponse principale est là.
La fonctionnalité «fractionnée» dans
bash
et d'autres dérivés du Bourne shell est obtenue de la manière la plus nette avec$IFS
le séparateur inter-champs. Par exemple, pour définir les arguments de position ($1
,$2
, ...) aux éléments de PATH, utilisez:Cela fonctionnera bien tant qu'il n'y aura pas d'espace dans $ PATH. Le faire fonctionner pour les éléments de chemin contenant des espaces est un exercice non trivial - laissé pour le lecteur intéressé. Il est probablement plus simple de le gérer en utilisant un langage de script tel que Perl.
J'ai aussi un script,
clnpath
que j'utilise beaucoup pour définir mon PATH. Je l'ai documenté dans la réponse à " Comment éviter de dupliquer la variable PATH dans csh ".la source
Ce qui rend ce problème ennuyeux, ce sont les cas de clôture parmi les premier et dernier éléments. Le problème peut être résolu avec élégance en changeant IFS et en utilisant un tableau, mais je ne sais pas comment réintroduire les deux points une fois que le chemin est converti en tableau.
Voici une version légèrement moins élégante qui supprime un répertoire de l'
$PATH
utilisation de la manipulation de chaînes uniquement. Je l'ai testé.la source
Voici un one-liner Perl:
La
$a
variable obtient le chemin à supprimer. Les commandess
(substitut) etprint
opèrent implicitement sur la$_
variable.la source
Bon truc ici. J'utilise celui-ci pour éviter d'ajouter des dupes en premier lieu.
la source
case ":$PATH:" in (*:"$nodup":*) ;; (*) PATH="$PATH:$nodup" ;; esac
Avec le globbing étendu activé, il est possible d'effectuer les opérations suivantes:
la source
Un-liner globbing étendu (enfin, en quelque sorte):
Il ne semble pas nécessaire d'échapper aux barres obliques dans $ 1.
la source
En ajoutant des deux points à PATH, nous pourrions également faire quelque chose comme:
la source
Dans path_remove_all (par proxxy):
la source
Bien que ce soit un fil très ancien, j'ai pensé que cette solution pourrait être intéressante:
trouvé sur ce billet de blog . Je pense que j'aime le plus celui-ci :)
la source
J'ai adopté une approche légèrement différente de celle de la plupart des gens ici et je me suis concentré spécifiquement sur la manipulation des cordes, comme ceci:
Ce qui précède est un exemple simplifié des fonctions finales que j'utilise. J'ai également créé
path_add_before
etpath_add_after
vous permet d'insérer un chemin avant / après un chemin spécifié déjà dans PATH.L'ensemble complet des fonctions est disponible dans path_helpers.sh dans mes dotfiles . Ils prennent entièrement en charge la suppression / l'ajout / l'ajout / l'insertion au début / au milieu / à la fin de la chaîne PATH.
la source