Risposte:
Aggiungendo alla famiglia di soluzioni :-).
duplicator.sh:
for i; do echo -n "$i $i "; done; echo
Rendi eseguibile e ora:
$ ./duplicator.sh dog cat bird whale
dog dog cat cat bird bird whale whale
In alternativa come funzione shell, ad esempio per essere riutilizzabile all'interno di uno script:
duplicator() {
for i; do echo -n "$i $i "; done; echo
}
che può quindi essere eseguito direttamente dove definito come
duplicator dog cat bird whale
Puoi usare sed:
sed -r 's/(\S+)/\1 \1/g' filename
Se si desidera salvare le modifiche sul file sul posto, dire:
sed -i -r 's/(\S+)/\1 \1/g' filename
Puoi anche usare perl:
perl -M5.10.0 -ne 'say join " ", map{$_, $_} split " ";' filename
(Aggiungi l' -iopzione per salvare le modifiche al file sul posto.)
Oppure, come suggerito da Terdon :
perl -M5.10.0 -ane 'say join " ", map{$_, $_} @F;' filename
Citando da perlvar:
@FL'array
@Fcontiene i campi di ciascuna riga letta quando è attivata la modalità autosplit. Vedi perlrun per l'-ainterruttore. Questo array è specifico del pacchetto e deve essere dichiarato o assegnato un nome pacchetto completo se non in pacchetto principale quando è in esecuzione sottostrict 'vars'.
sed -r 's/\S+/& &/g'.
-a:perl -M5.10.0 -ane 'say join " ", map{$_, $_} @F;'
Cosa sarebbe questo senza una awk/gawkrisposta:
$ awk '{ for(i=1;i<=NF+1;i+=1/2) { printf("%s ",$i); }}' <<<"dog cat bird whale"
dog dog cat cat bird bird whale whale
Se una riga di chiusura è importante:
$ awk '{ for(i=1;i<=NF+1;i+=1/2) { printf("%s ",$i); }} END{print ""}' <<<"dog cat bird whale"
for(i=1;i<=NF;++i) printf "%s %s ",$i,$i;è sia più breve che più leggibile, IMHO.
s="dog cat bird wale"
ss=$( tr ' ' '\n' <<< "$s" | sed p | tr '\n' ' ' )
echo "$ss"
dog dog cat cat bird bird wale wale
sed -n 'p;p'- ho pensato che fosse più trasparente su ciò che sta facendo.
Se hai la tua stringa in una variabile, ad esempio foo="dog cat bird whale", potresti fare:
Bash puro:
$ echo "$foo" | (read a b c d && echo "$a $a $b $b $c $c $d $d")
dog dog cat cat bird bird whale whale
Spiegazione: Le parentesi sono necessarie affinché la reade echoavvengano nella stessa sottostruttura e possano quindi condividere le variabili. Senza di essi, echosi stamperebbe solo una riga vuota.
coreutils:
$ join -j 5 -o 1.1,1.1,1.2,1.2,1.3,1.3,1.4,1.4 <(echo $foo) <(echo)
dog dog cat cat bird bird whale whale
Spiegazione: Il -oflag di joinconsente di impostare il formato di output. Qui, gli sto dicendo di stampare il 1 ° campo del 1o file ( 1.1), seguito dal 2o campo del 1o file ( 1.2) ecc. In questo modo ogni campo del 1o file viene stampato due volte. Tuttavia, joinè progettato per unire due linee di input su un campo comune. Quindi, gli passo anche una riga vuota ( <(echo)) e quindi la ignoro. I -jset le uniscono campo, impostandolo a uno che non esiste (il 5 °) causa joinper stampare l'intera linea.
Se non ti interessa lo spazio bianco o l'ordine di input, puoi farlo
$ paste <(echo $foo) <(echo $foo)
dog cat bird wale dog cat bird walePerl 1:
$ echo $foo | perl -lane 'push @k, $_,$_ for @F; print "@k"'
dog dog cat cat bird bird whale whale
Spiegazione:
-l: adds a newline to each print call (among other things)
-a: turns on field splitting, fields are saved as @F
-n: process input line by line
-e: give a script as a command line parameter.
Lo script sopra salverà ogni campo (da @F) due volte nell'array @ke quindi stamperà @k. Se non hai bisogno della nuova riga finale, puoi semplificare
$ echo $foo | perl -ane 'print " $_ $_" for @F'Perl 2:
$ echo $foo | perl -0040 -pne 'print "$_"' | paste - -
dog dog cat cat bird bird whale whale
Spiegazione: L' -0opzione imposta il separatore del record di input (come numero esadecimale o ottale, vedere qui per le conversioni). Qui, lo sto impostando su ottale 040che è uno spazio. I -pmarchi perlstampano ogni ingresso "line" e poiché abbiamo impostato il separatore di record di spazio, le linee sono ora definiti da spazi, così ogni campo viene stampata due volte.
awk:
$ echo $foo | awk '{for(i=1;i<=NF;i++){$i=$i" "$i;} 1;}'
dog dog cat cat bird bird whale whale
Spiegazione: NF è il numero di campi, quindi lo script sopra passa attraverso ogni campo e lo aggiunge a se stesso. Una volta fatto, stampiamo la linea ( 1;è solo una scorciatoia per la stampa).
Ora per una pythonrisposta:
Dalla riga di comando:
$ python -c "import sys; s=sys.argv[1:]; print(' '.join(j for i in zip(s,s)for j in i));" dog cat bird whale
Dallo stdin:
$ python -c "s=input().split(); print(' '.join(j for i in zip(s,s)for j in i));" <<<"dog cat bird whale"
Il risultato in entrambi i casi:
dog dog cat cat bird bird whale whale
Un altro approccio, usando anche solo builtin bash
$ string="dog cat bird whale"
$ twix() { while [[ ! -z $1 ]]; do printf "%s %s " $1 $1; shift; done; }
$ twix $string
dog dog cat cat bird bird whale whale
Non vedo alcun vantaggio rispetto alla risposta principale, solo per mostrare un modo leggermente diverso, che potrebbe essere più adatto per alcuni scopi.
echoè anche una shell integrata in Bash (test type echo).