Explication nécessaire sur la façon dont je peux répéter un caractère dans le shell POSIX

8

La réponse suivante sur Stack Overflow,

Comment puis-je répéter un personnage en bash?

impose une manière plausible de répéter POSIX -un seul caractère, comme suit. Dans cet exemple, utilisons le signe égal 100 fois:

printf %100s | tr " " "="

Mon problème est que je ne comprends pas comment cela fonctionne et je préférerais une explication simple. Veuillez vous abstenir de commentaires comme lire le manuel , je l'ai fait, et comme je ne suis pas intelligent, je pose cette question car je n'ai jamais utilisé tr, ni vu une telle printfdéclaration.

LinuxSecurityFreak
la source

Réponses:

13

En bref, printf %100simprimera 100 espaces et tr " " "="convertira ces espaces en signes égaux, imprimant efficacement 100 signes égaux.

Décomposer:


printfest un shell intégré. Il prend généralement deux arguments ou plus, le premier étant une "chaîne de format" et le reste sera utilisé pour remplir des espaces réservés dans cette chaîne de format. Une fois ce modèle entièrement rempli, il imprimera le résultat. S'il reste plus d'arguments, il recommencera, remplissant plus d'arguments et imprimant la chaîne résultante.

La chaîne de format utilisée pour printfprend les spécifications de format, qui commencent %et se terminent par une seule lettre, donc %dsignifie un entier (en utilisant la base décimale, donc "d"), %fsignifie un nombre à virgule flottante et %ssignifie une chaîne de caractères. Les caractères autres que les lettres après le %sont des modificateurs de la spécification de format et, en particulier, des nombres sont utilisés pour spécifier la longueur demandée du champ en sortie. Donc %100s, formatera la chaîne pour avoir au moins 100 caractères, il la remplira d'espaces et la gardera alignée à droite (en d'autres termes, ajoutez des espaces au début de la chaîne.)

Si un argument supplémentaire est passé, il l'utilisera pour ce %schamp, donc par exemple, printf %100s abcaffichera 97 espaces (pour atteindre 100 au total, en considérant les 3 dans "abc") suivi de la chaîne réelle "abc". Mais si aucun argument n'est donné, la spécification de format est remplie avec un argument vide ou nul (qui est une chaîne vide pour %s, ce serait 0 pour %d, etc.) C'est donc la même chose que si une chaîne vide était passée, comme printf %100s ''. Le résultat final est que seul le remplissage de 100 caractères est imprimé.

Donc, en rassemblant le tout, vous printf %100sobtenez 100 espaces imprimés.


Maintenant, trc'est un outil pour traduire les caractères de l'entrée à la sortie. Il prend deux arguments, SET1 et SET2, chacun un ensemble de caractères, puis traduit le premier caractère de SET1 en premier de SET2, le deuxième caractère de SET1 en deuxième de SET2 et ainsi de suite. trlit son entrée depuis stdin et l'écrit sur stdout (il est donc très utile dans des pipelines comme celui ci-dessus.) trtraduira toujours toutes les occurrences de ce caractère dans une chaîne donnée.

Par exemple, tr aeiou 12345traduira les voyelles minuscules dans les nombres 1 à 5 dans cet ordre, donc il traduira "file d'attente" en "q52523ng" par exemple. Vous pouvez également lui transmettre des plages de caractères, de manière tr a-z A-Zà transformer n'importe quelle lettre minuscule en lettre majuscule correspondante.

Il en tr " " "="va de même pour la traduction des espaces en signes égaux tout au long de la chaîne. Le premier espace doit être cité pour être reconnu comme argument. Le =n'a pas besoin d'être cité, mais cela ne fait pas de mal. tr " " =aurait fonctionné de la même manière.


En rassemblant le tout, imprimez 100 espaces, puis traduisez chacun d'eux en signes égaux.

J'espère que cela l'explique suffisamment en détail, mais s'il y a encore quelque chose que vous ne comprenez pas, veuillez laisser un commentaire et je vais essayer de répondre à cela.

filbranden
la source
En vérifiant simplement, les éléments suivants seraient-ils plus corrects sur le plan syntaxique?:printf '%100s' ' ' | tr " " "="
LinuxSecurityFreak
2
@Vlastimil En fait printf '%100s' '', avec une chaîne vide ... J'ai mis à jour la réponse pour l'inclure. Dans ce cas particulier, une chaîne vide ou un seul espace ne ferait pas de différence, mais vous pouvez voir une différence dans printf '%sx\n', qui est identique à printf '%sx\n' ''mais différent de printf '%sx\n' ' '. J'espère que ça aide!
filbranden
1
+1 pour la mention qui trfonctionne sur des ensembles de caractères. Ceci est souvent omis.
Sergiy Kolodyazhnyy
11

La printfcommande utilise son premier argument comme format pour imprimer ses arguments suivants. printf %100simprime ses arguments remplis à 100 caractères de large, en utilisant des espaces (à gauche). Aucun argument n'est fourni pour formater, il formate donc la chaîne vide une fois et génère 100 espaces. Tu peux voir ça:

$ printf %100s | hexdump -C
00000000  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
*
00000064

(20 est l'hex pour un espace; *signifie la ligne précédente répétée)

Les chaînes de format utilisent approximativement les Xprintfspécificateurs C :, %une largeur facultative pour s'adapter à la valeur formatée et un type de format à utiliser. sest le formatage des chaînes et les chaînes sont complétées par des espaces à gauche par défaut. Il peut y avoir plusieurs formats ou d'autres parties littérales: printf "a%10sb\n" helloimpressions

 a         xb.

trremplace les caractères sélectionnés dans son entrée standard par des remplacements sélectionnés et imprime le résultat sur sa sortie standard. tr " " "="a un seul caractère à remplacer - un espace - et un seul caractère pour le remplacer - un signe égal. Il transforme ainsi chaque espace de son entrée en un =et laisse le reste inchangé. Vous pouvez également essayer cela:

$ tr " " "="
hello world
hello=world

(J'ai tapé le "bonjour le monde")

Vous pouvez avoir plusieurs remplacements: tr abc deftransforme a en d, b en e, c en f et laisse le reste inchangé. Ici, ce n'est qu'un seul personnage, car c'est ce qui printfpourrait générer à moindre coût.

Le tuyau |fait que la sortie de la commande de gauche printf %100s,, sera utilisée comme entrée de la commande de droite tr " " "=",. Autrement dit, une centaine d'espaces consécutifs sont attribués à tr, et chacun d'eux est remplacé par un =, avec la nouvelle chaîne imprimée.

printf %100s | tr " " "="
====================================================================================================
Michael Homer
la source
En vérifiant simplement, les éléments suivants seraient-ils plus corrects sur le plan syntaxique?:printf '%100s' ' ' | tr " " "="
LinuxSecurityFreak
1
Le formatage d'un espace et son remplissage avec des espaces donneront la même sortie que le formatage d'une chaîne vide et le remplissage avec des espaces, mais ce n'est pas structurellement équivalent. C'est peut-être plus «correct» en termes de clarté sur ce qui se passe, mais pas syntaxiquement, et ce sont des commandes différentes.
Michael Homer