Spiegazione necessaria su come posso ripetere un personaggio nella shell POSIX


8

La seguente risposta su Stack Overflow,

Come posso ripetere un personaggio in bash?

impone un modo plausibile di POSIX: ripetere ripetutamente un singolo carattere, come segue. In questo esempio usiamo il segno di uguale 100 volte:

printf %100s | tr " " "="

Il mio problema è che non capisco come funziona e preferirei una spiegazione semplice. Ti prego di astenermi da commenti come leggere il manuale , l'ho fatto, e poiché non ne sono intelligente, sto facendo questa domanda come non ho mai usato tr, né ho visto una simile printfaffermazione.

Risposte:


13

In breve, printf %100sstamperà 100 spazi e tr " " "="li convertirà in segni uguali, stampando efficacemente 100 spazi uguali.

Abbattendo:


printfè una shell integrata. In genere sono necessari due o più argomenti, il primo dei quali è una "stringa di formato" e il resto verrà utilizzato per riempire i segnaposto in quella stringa di formato. Una volta riempito completamente, il modello stamperà il risultato. Se sono rimasti più argomenti, ricomincerà, riempiendo più argomenti e stampando la stringa risultante.

La stringa di formato utilizzata printfprende le specifiche di formato, che iniziano con %e terminano con una singola lettera, quindi %dsignifica un numero intero (usando la base decimale, quindi "d"), %findica un numero in virgola mobile e %suna stringa di caratteri. I caratteri diversi dalle lettere dopo il %sono modificatori per la specifica del formato e, in particolare, i numeri vengono utilizzati per specificare la lunghezza richiesta del campo in uscita. Quindi %100sformatterà la stringa in modo che abbia almeno 100 caratteri, la riempirà di spazi e la manterrà allineata a destra (in altre parole, aggiungi spazi all'inizio della stringa).

Se viene passato un argomento in più, lo userebbe per quel %scampo, quindi ad esempio printf %100s abcstamperà 97 spazi (per arrivare a 100 totali, considerando il 3 in "abc") seguito dalla stringa effettiva "abc". Ma se non viene fornito alcun argomento, la specifica del formato viene riempita con un argomento vuoto o nullo (che è una stringa vuota per %s, sarebbe 0 per %d, ecc.) Quindi è lo stesso che se fosse passata una stringa vuota, come printf %100s ''. Il risultato finale è che viene stampata solo l'imbottitura di 100 caratteri.

Quindi, mettendo tutto insieme, si printf %100sottengono 100 spazi stampati.


Ora trè uno strumento per tradurre i caratteri da input a output. Prende due argomenti, SET1 e SET2, ciascuno un insieme di caratteri, quindi traduce il primo carattere di SET1 nel primo di SET2, il secondo carattere di SET1 nel secondo di SET2 e così via. trlegge il suo input da stdin e lo riscrive su stdout (quindi è molto utile in pipeline come quella sopra.) trtradurrà sempre tutte le occorrenze di quel carattere in una data stringa.

Ad esempio, tr aeiou 12345tradurrà le vocali minuscole nei numeri da 1 a 5 in quell'ordine, quindi tradurrà "accodamento" in "q52523ng" per esempio. Puoi anche passare intervalli di caratteri, ad esempio tr a-z A-Zper trasformare qualsiasi lettera minuscola nella lettera maiuscola corrispondente.

Quindi tr " " "="sta semplicemente traducendo spazi in segni uguali in tutta la stringa. Il primo spazio deve essere citato per essere riconosciuto come argomento. In =realtà non è necessario che sia citato, ma farlo non fa male. tr " " =avrebbe funzionato allo stesso modo.


Mettendo tutto insieme, stampare 100 spazi, quindi tradurli ciascuno in segni uguali.

Spero che questo lo spieghi in modo sufficientemente dettagliato, ma se c'è ancora qualcosa che non capisci, per favore lascia un commento e proverò ad affrontarlo.


Solo controllando, quanto segue sarebbe più sintatticamente corretto ?:printf '%100s' ' ' | tr " " "="
LinuxSecurityFreak

2
@Vlastimil In realtà printf '%100s' '', con una stringa vuota ... Ho aggiornato la risposta per includerla. In questo caso particolare, una stringa vuota o un singolo spazio non farebbero differenza, ma puoi vedere una differenza printf '%sx\n', che è la stessa printf '%sx\n' ''ma diversa da printf '%sx\n' ' '. Spero che aiuti!
Filbranden,

1
+1 per menzione che tropera su set di caratteri. Questo è spesso escluso.
Sergiy Kolodyazhnyy,

11

Il printfcomando usa il suo primo argomento come formato per stampare i suoi argomenti successivi. printf %100sstampa i suoi argomenti riempiti con una larghezza di 100 caratteri, usando gli spazi (a sinistra). Non viene fornito alcun argomento per formattare, quindi formatta una volta la stringa vuota e genera 100 spazi. Potete vederlo:

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

(20 è l'esagono per uno spazio; *indica la riga precedente ripetuta)

Le stringhe di formato utilizzano approssimativamente gli Xprintfidentificatori C :, %una larghezza opzionale per adattare il valore formattato e un tipo di formato da utilizzare. sè la formattazione delle stringhe e le stringhe sono riempite con spazi a sinistra per impostazione predefinita. Potrebbero esserci più formati o altre parti letterali: printf "a%10sb\n" hellostampe

 a         xb.

trsostituisce i caratteri selezionati nel suo input standard con i ricambi selezionati e stampa il risultato sul suo output standard. tr " " "="ha un singolo carattere da sostituire - uno spazio - e un singolo carattere con cui sostituirlo - un segno di uguale. Trasforma così ogni spazio nel suo input in un =e lascia il resto invariato. Puoi provare anche quello:

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

(Ho scritto il "ciao mondo")

Potresti avere più sostituzioni: tr abc deftrasforma a in d, b in e, c in f e lascia invariato il resto. Qui è solo un singolo personaggio, poiché era quello che printfpoteva generare a buon mercato.

La pipe |fa sì che l'output del comando a sinistra, printf %100sda utilizzare come input per il comando a destra tr " " "=",. Cioè, vengono assegnati un centinaio di spazi consecutivi tre ognuno di essi viene sostituito da un =, con la nuova stringa stampata.

printf %100s | tr " " "="
====================================================================================================

Solo controllando, quanto segue sarebbe più sintatticamente corretto ?:printf '%100s' ' ' | tr " " "="
LinuxSecurityFreak

1
La formattazione di uno spazio e il suo riempimento con spazi darà lo stesso output della formattazione di una stringa vuota e del riempimento con spazi, ma non è strutturalmente equivalente. Forse è più "corretto" in termini di chiarezza su ciò che sta accadendo, ma non sintatticamente, e sono comandi diversi.
Michael Homer,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.