1
votes

Utilisez sed pour vous assurer qu'une variable bash se termine toujours par un signe%

J'écris un script de passe-temps bash (en cours d'apprentissage de la commande sed ). J'ai écrit une fonction qui prend zéro ou un argument et appelle la commande pactl avec le dernier argument se terminant toujours par un signe % . La commande pactl contrôle les haut-parleurs de ma machine ubuntu . Je peux changer le volume en l'utilisant et même l'augmenter au-delà de 100% . Par exemple, pour régler le volume à 150%, j'utilise:

echo "150%" | sed -n 's/\([^%]*\)%?/\1/p'

echo "150%" | sed -n 's/\([^%]*\)%/\1/p'

echo "150%" | sed -n 's/\(\d+\)/\1/p'

echo "150%" | sed -n 's/\(\d+\)%/\1/p'

echo "150%" | sed -n 's/\(\d+\)%?/\1/p'

La fonction que j'ai écrite avec juste des arguments check:

function increase {
    if [ "$#" -eq 2 ]; then
        pactl set-sink-volume $@
    elif [ "$#" -eq 1 ]; then
        pactl set-sink-volume 0 $1%
    fi
}

Maintenant, si un utilisateur ne passe qu'un seul argument, je veux m'assurer qu'il n'y a qu'un seul signe % à la fin de l'argument. Donc, je veux juste extraire le nombre en utilisant sed et ajouter explicitement le signe% à la fin du nombre.

J'ai essayé la combinaison suivante mais elles ne fonctionnent pas:

pactl set-sink-volume 0 150%

Par "ne fonctionne pas", je veux dire quand j'essaie de passer à la fois 150 et 150% (écho "150" et écho "150%" à des moments différents), cela ne fonctionne pas ne donne pas le bon résultat à un moment ou à un autre.


1 commentaires

Aucune idée, mais pour info, très peu d'outils UNIX (aucun des outils standard) reconnaîtraient \ d comme signifiant "chiffre". Utilisez toujours [0-9] ou [[: digit:]] à la place.


5 Réponses :


3
votes

Si j'ai correctement répondu à votre question, pourriez-vous essayer de suivre.

echo "150%" | awk 'BEGIN{FS=OFS="%"} {print $1,""}'

Le résultat sera 150 . Maintenant, si nous exécutons avec echo "150" comme suit:

echo "150%" |      ##echoing 150% and using pipe(|) sending its standard output as input to sed command.
sed '              ##Starting sed command from here.
s                  ##Using s option for using substitution.
/\([^%]*\)%.*      ##Using memory buffer capability by taking everything before 1st occurrence of % and save it into (...) escaping \( and \) to remove its special meaning. Then mentioning % and everything else.
/\1/               ##Now mentioning \1  means substitute complete Line with only matched 1st memory buffer value.
'

La sortie sera toujours 150

OU au cas où vous souhaiteriez également utiliser % en sortie (après avoir vu la réponse de @oguz ismail ajoutant ceci):

echo "150" | sed 's/\([^%]*\)%.*/\1%/'

OU

echo "150%" | sed 's/\([^%]*\)%.*/\1%/'

Explication de la commande sed : Voici l'explication de sed c'est uniquement à des fins d'explication.

echo "150" | sed 's/\([^%]*\)%.*/\1/'


Avec awk réponse: Si vous êtes d'accord avec awk réponse:

echo "150%" | sed 's/\([^%]*\)%.*/\1/'


0 commentaires

2
votes

Capturez la partie numérique, ajoutez % dans le remplacement. Par exemple:

sed -En 's/^([0-9]+)%*/\1%/p'

Avec GNU sed, il peut être raccourci à:

sed -n 's/^\([0-9]\{1,\}\)%*/\1%/p'

Je préférerais le mécanisme de correspondance des expressions régulières de bash à sed pour valider et nettoyer un tel argument.


8 commentaires

Qu'est-ce qui n'allait pas dans ma mise en œuvre? Je sais que je n'ai pas ajouté% dans ma chaîne de remplacement, mais cela aurait dû extraire au moins la partie numérique de l'expression.


@abhiarora Par défaut, sed utilise Expressions régulières de base ; qui ne prend pas en charge ? , + et \ d


Et celui-ci echo "150%" | sed -n 's / \ ([^%] * \)% / \ 1 / p' fonctionne, il extrait le nombre


mais cela ne fait pas écho "150" | sed -n 's / \ ([^%] * \)% / \ 1 / p' et echo "150 %%" | sed -n 's / \ ([^%] * \)% / \ 1 / p'


@abhiarora Oui. Le premier essaie de faire correspondre un % après le nombre, mais il n'y a pas de % en entrée. Wrt le second, il correspond à 150% , et le remplace par 150 ; il ne touche pas le % supplémentaire à la fin.


Pourquoi \ d ne fonctionne pas mais [0-9] fonctionne dans sed -En . N'importe quelle raison?


\ d ne fait pas partie de Expressions régulières POSIX < / a>. Les implémentations peuvent ou non fournir cette extension, il semble que celle que vous n'utilisez pas


Je ne sais pas pourquoi ma question a été rejetée! Merci pour votre réponse!



2
votes

Le problème avec votre réponse est que vous utilisez '\ d' et sed n'offre pas cette extension regex. Vous pouvez cependant utiliser les classes de caractères Posix, vous pouvez donc faire quelque chose comme:

echo "150 %%" | sed -E 's / ^ ([^ [: chiffre:]] *) ([[: chiffre:]] +) (. * $) / \ 2% /'


0 commentaires

1
votes

Vous avez obtenu la réponse sed que vous recherchiez, mais pour info, vous n'utiliseriez pas sed pour un travail comme celui-ci, juste une substitution de shell:

$ cat tst.sh
#!/usr/bin/env bash

function increase {
    if [ "$#" -eq 2 ]; then
        echo pactl set-sink-volume "$@"
    elif [ "$#" -eq 1 ]; then
        echo pactl set-sink-volume 0 "${1%\%}%"
    fi
}

increase "$@"

$ ./tst.sh 3 4
pactl set-sink-volume 3 4

$ ./tst.sh 150
pactl set-sink-volume 0 150%

$ ./tst.sh 150%
pactl set-sink-volume 0 150%


1 commentaires

C'est vraiment quelque chose que je ne sais pas. Merci d'avoir partagé!



1
votes

Si vous souhaitez utiliser GNU sed, vous pouvez le faire:

echo "150%" | sed -nr 's/([[:digit:]]+).?/\1/p'
150

echo "150%" | sed -nr 's/([[:digit:]]+).?/\1%/p'
150%

Option "-r" pour une expression régulière étendue (pas besoin d'utiliser fréquemment "\") p >


0 commentaires