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.
5 Réponses :
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/'
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.
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!
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% /'
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%
C'est vraiment quelque chose que je ne sais pas. Merci d'avoir partagé!
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 >
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.