web-dev-qa-db-fra.com

Comment cette commande de substitution 'sed' avec beaucoup de signes @ fonctionne-t-elle?

Quelqu'un peut-il expliquer le fonctionnement de cette commande sed?

sed 's@+@ @g;s@%@\\x@g' | xargs -0 printf "%b"
8
Raj

Dans sed, les commandes de substitution sont généralement écrites sous la forme s/pattern/replacement/options. Cependant, il n'est pas nécessaire d'utiliser / - vous pouvez utiliser d'autres caractères si cela vous convient. Il peut donc s'agir de s@pattern@replacement@options ou s:foo:bar:g. s@+@ @g est comme s/+/ /g - remplace tout + par des espaces. De même, s@%@\\x@g remplace tout % par \x (une simple barre oblique inversée est un caractère d'échappement dans sed, vous avez donc besoin de deux pour obtenir une barre oblique inverse réelle).

Une chaîne telle que foo+%2Fbar deviendra alors foo \x2Fbar. printf "%b" développera les séquences échappées par une barre oblique inversée telles que \x2F (le caractère ASCII dont la valeur hexadécimale est 2F, qui est /) pour vous donner finalement foo /bar.

15
muru

La commande que vous demandez pour décoder les séquences +es et % à partir d'URL n'est pas simplement une commande sed, c'est un pipeline qui traite les entrées avec sed =, puis le dirige vers xargs pour un traitement ultérieur. Premièrement, regardons la commande sed:

sed 's@+@ @g;s@%@\\x@g'

Vous serez peut-être plus habitué à le voir avec / plutôt que @ comme séparateur, ce qui aurait pu être facilement fait ici sans complication, puisque / n'apparaît ni dans les modèles de recherche ni dans l'un des textes de remplacement. Cette commande est équivalente:

sed 's/+/ /g;s/%/\\x/g'

Comme /, @ est un caractère de ponctuation tout à fait approprié pour sed.

Sur chaque ligne d'entrée:

  1. s@+@ @g (s/+/ /g) remplace (s) les occurrences de + par un espace. Ceci affecte tous les +es d'une ligne (g), pas seulement la première.

  2. ; termine l'action ("commande") et vous permet d'en spécifier une autre dans le même "script".

  3. s@%@\\x@g (s/%/\\x/g) remplace (s) les occurrences de % par \x. Comme auparavant, il agit sur tous les éléments plutôt que sur le premier de chaque ligne (g).

    Dans \\x le \\ représente un seul \ car \ a une signification particulière pour sed. Sa signification particulière est en fait le caractère que vous utilisez pour supprimer la signification spéciale d'un autre caractère qui le suit et qui aurait autrement une signification spéciale. Donc, il doit être échappé en tant que \\.


Examinons maintenant la commande xargs, dont le but est d’exécuter printf .

xargs construit des lignes de commande. Si vous exécutez xargs command..., où command... correspond à un ou plusieurs Word, xargs s'exécute command... avec des arguments supplémentaires en ligne de commande lu depuis son entrée. Dans ce cas, l'entrée à xargs est la sortie de sed, en raison du canal (|). Normalement, xargs interprète tout espace blanc dans son entrée comme signifiant que le texte avant et après constitue des arguments séparés, mais l’option -0 lui permet de scinder les arguments aux occurrences de caractère null .

Dans l'utilisation prévue de votre commande, un caractère null n'apparaîtra pas et xargs exécutera printf %b avec un seul argument de ligne de commande supplémentaire, le résultat de la commande sed. Ainsi, bien qu’il ne soit pas équivalent en général, dans ce cas, tout le pipeline aurait plutôt pu être écrit comme ceci en utilisant substitution de commande au lieu de xargs:

printf '%b\n' "$(sed 's/+/ /g;s/%/\\x/g')"

Quant à ce que printf est censé faire ici, comme dit muru le spécificateur de format %b utilise et affiche un argument (comme %s ) mais provoque des échappements de barre oblique inverse - du type de tri, la commande sed située à gauche du canal a été écrite pour générer - pour être traduit en caractères qu'ils représentent .

Supposons que je lance cette commande et passe http://foldoc.org/debugging%20by%20printf en entrée. Je reçois http://foldoc.org/debugging by printf en sortie, car les séquences %20 sont traduites en espaces.

10
Eliah Kagan

C’est la beauté de sed, elle applique ses paradigmes à elle-même ... Après la commande (telle que s ou tr ou rien), le caractère suivant est considéré comme le séparateur.

Vous devez choisir judicieusement pour éviter toute interférence avec Shell et la commande elle-même, et de garder la chose lisible, mais il est parfaitement valide d'écrire quelque chose d'aussi horrible que:

echo 'arrival' | sed srarbrg

... et obtenez brrivbl en conséquence, ce à quoi vous vous attendez. Vous pouvez vous amuser à le rendre vraiment cryptique, comme dans:

echo 'arrival' | sed s\fa\fb\fg   # \f is form feed, chr(12)

L'utilisation courante consiste à utiliser la barre oblique comme délimiteur, mais lorsque votre expression contient le délimiteur, il est plus facile de saisir l'intention. Votre délimiteur peut être compris dans la plage ASCII8 (les délimiteurs multi-octets tels que £ provoquent une erreur).

Rappelez-vous simplement que l'objectif est de rendre les choses plus faciles, pas plus cryptiques.

3
Marabiloso