3
votes

Remplacement de la variable PS1 dans .bashrc en utilisant Sed ou Perl

J'essaie de remplacer une ligne dans le fichier et je rencontre des problèmes.

Fichier d'origine:

export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"

Commande que j'exécute:

export PS1="
[e[32;1m][[e[37;1m]@h:[e[37;1m]w[e[32;1m]]\$ [e[0m]

Message d'erreur:

sed -i 's~PS1.*~PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]~g' ~/.bashrc

J'ai aussi essayé sed:

syntax error at -e line 1, near "e["
Execution of -e aborted due to compilation errors.

Résultat avec Sed:

perl -pi -e 's~PS1.*~PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]~g' ~/.bashrc
Fichier de résultat attendu:
export PS1='\h:\w\$ '

Résultat final

Cela n'a pas grand-chose à faire avec la question sauf à montrer aux gens à quoi ressemblera la PS1 lorsqu'elle fonctionnera correctement

 entrez la description de l'image ici


1 commentaires

Merci d'inclure des instructions claires pour la reproduction, ainsi que les résultats attendus et réels! Vous devriez également prendre le temps d'essayer de réduire le problème. Par exemple, ce problème n'est pas spécifique à PS1, et un MCVE pourrait être "Pourquoi echo" foobar "| sed 's / foo / \ n /' génère un saut de ligne + barre au lieu de \ nbar ? " Voir Combien d'efforts de recherche sont attendus de Stack Overflow utilisateurs?


3 Réponses :


1
votes

Pour sed , vous devez échapper chaque barre oblique inverse avec une autre barre oblique inverse pour qu'elles soient traitées littéralement.

La commande s vous oblige également à échapper le délimiteur & , il est donc plus facile d'utiliser la commande c , de sorte que doubler les contre-obliques est la seule exigence:

hello
export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"
world

Si file.txt contient:

hello
PS1=foo
world

puis après avoir exécuté cette commande, il contiendra:

sed -i '/PS1/c\
export PS1="\\n\\[\\e[32;1m\\][\\[\\e[37;1m\\]\\u@\\h:\\[\\e[37;1m\\]\\w\\[\\e[32;1m\\]]\\\\$ \\[\\e[0m\\]"
' file.txt


0 commentaires

0
votes

Utilisez simplement un outil qui peut fonctionner avec des chaînes littérales, par exemple awk:

$ new='"\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"' \
    awk 'sub(/PS1=.*/,"PS1="){$0=$0 ENVIRON["new"]} 1' file
export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"

ou si vous préférez:

$ awk 'BEGIN{new=ARGV[1]; ARGV[1]=""} sub(/PS1=.*/,"PS1="){$0=$0 new} 1' \
    '"\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"' file
export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"

sed ne dispose d'aucun mécanisme pour comprendre les chaînes littérales, voir Est-il possible d'échapper de manière fiable aux métacaractères regex avec sed pour les cerceaux que vous devez franchir pour que sed agisse comme si c'était le cas.


0 commentaires

0
votes

Vous pouvez le faire en utilisant du code Bash pur avec:

newps1='"\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"'
readarray -t bashrc_lines <~/.bashrc
printf '%s\n' "${bashrc_lines[@]/PS1=*/PS1=$newps1}" >~/.bashrc

Le seul guillemet requis est de mettre des guillemets simples autour de la chaîne exacte (y compris les guillemets doubles) à mettre dans le à droite de PS1=.

Le code nécessite Bash 4 (ou 5) pour readarray . Il lit tout le fichier '.bashrc' en mémoire, mais cela ne devrait pas poser de problème en pratique. (S'il est trop gros pour être chargé en mémoire, il est certainement trop gros pour être un '.bashrc' utile.)

Voir Remplacement d'une partie d'une chaîne (BashFAQ / 100 (Comment faire une manipulation de chaîne dans bash?)) pour plus d'informations sur la façon dont la substitution est effectuée.


0 commentaires