Antworten:
Erweiterung der Lösungsfamilie :-).
duplicator.sh
:
for i; do echo -n "$i $i "; done; echo
Ausführbar machen und jetzt:
$ ./duplicator.sh dog cat bird whale
dog dog cat cat bird bird whale whale
Alternativ als Shell-Funktion, um zB innerhalb eines Skripts wiederverwendbar zu sein:
duplicator() {
for i; do echo -n "$i $i "; done; echo
}
die dann direkt ausgeführt werden können, wo definiert als
duplicator dog cat bird whale
Sie könnten verwenden sed
:
sed -r 's/(\S+)/\1 \1/g' filename
Wenn Sie die Änderungen an der Datei direkt speichern möchten, sagen Sie:
sed -i -r 's/(\S+)/\1 \1/g' filename
Sie könnten auch verwenden perl
:
perl -M5.10.0 -ne 'say join " ", map{$_, $_} split " ";' filename
(Fügen Sie die -i
Option hinzu, um die Änderungen an der Datei direkt zu speichern.)
Oder, wie von Terdon vorgeschlagen :
perl -M5.10.0 -ane 'say join " ", map{$_, $_} @F;' filename
Zitat aus perlvar
:
@F
Das Array
@F
enthält die Felder jeder eingelesenen Zeile, wenn der Autosplit-Modus aktiviert ist. Siehe perlrun für den-a
Schalter. Dieses Array ist paketspezifisch und muss deklariert oder mit einem vollständigen Paketnamen versehen werden, wenn es nicht unter package main ausgeführt wirdstrict 'vars'
.
sed -r 's/\S+/& &/g'
.
-a
:perl -M5.10.0 -ane 'say join " ", map{$_, $_} @F;'
Was wäre das ohne eine awk/gawk
Antwort:
$ 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
Wenn ein abschließender Zeilenumbruch wichtig ist:
$ 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;
ist sowohl kürzer als auch lesbarer, 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'
- ich dachte, dass das transparenter darüber ist, was es tut.
Wenn Sie Ihre Zeichenfolge in einer Variablen haben, foo="dog cat bird whale"
können Sie beispielsweise Folgendes tun:
Pure Bash:
$ echo "$foo" | (read a b c d && echo "$a $a $b $b $c $c $d $d")
dog dog cat cat bird bird whale whale
Erläuterung: Die Klammern werden benötigt, damit die read
und echo
in derselben Unterschale vorkommen und daher Variablen gemeinsam nutzen können. Ohne sie echo
würde das nur eine leere Zeile ausgeben.
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
Erläuterung: Mit dem -o
Flag von join
können Sie das Ausgabeformat festlegen. Hier sage ich, dass das erste Feld der ersten Datei ( 1.1
) gedruckt werden soll , gefolgt vom zweiten Feld der ersten Datei ( 1.2
) usw. Auf diese Weise wird jedes Feld der ersten Datei zweimal gedruckt. Es wurde jedoch join
entwickelt, um zwei Eingabezeilen in einem gemeinsamen Feld zu verbinden. Also übergebe ich ihm auch eine Leerzeile ( <(echo)
) und ignoriere sie dann. Die -j
Sätze kommen die Feld, es zu einer Einstellung , die nicht (5.) existiert bewirkt , dass join
die gesamte Zeile drucken.
Wenn Sie sich nicht für Leerzeichen oder die Eingabereihenfolge interessieren, können Sie dies tun
$ paste <(echo $foo) <(echo $foo)
dog cat bird wale dog cat bird wale
Perl 1:
$ echo $foo | perl -lane 'push @k, $_,$_ for @F; print "@k"'
dog dog cat cat bird bird whale whale
Erläuterung:
-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.
Das obige Skript speichert jedes Feld (von @F
) zweimal im Array @k
und druckt es dann aus @k
. Wenn Sie die nachgestellte Zeile nicht benötigen, können Sie sie vereinfachen
$ echo $foo | perl -ane 'print " $_ $_" for @F'
Perl 2:
$ echo $foo | perl -0040 -pne 'print "$_"' | paste - -
dog dog cat cat bird bird whale whale
Erläuterung: Die -0
Option stellt die Eingabe voneinander zu trennen sind (als hexadezimale oder Oktalzahl, siehe hier für Umtausche). Hier setze ich es auf oktal, 040
was ein Leerzeichen ist. Das -p
bewirkt perl
, dass jede Eingabe "zeilenweise" gedruckt wird, und da wir das Datensatztrennzeichen auf Leerzeichen gesetzt haben, werden Zeilen jetzt durch Leerzeichen definiert, sodass jedes Feld zweimal gedruckt wird.
awk
:
$ echo $foo | awk '{for(i=1;i<=NF;i++){$i=$i" "$i;} 1;}'
dog dog cat cat bird bird whale whale
Erläuterung: NF
Gibt die Anzahl der Felder an, sodass das obige Skript jedes Feld durchläuft und an sich selbst anfügt. Sobald dies erledigt ist, drucken wir die Zeile ( 1;
ist nur eine Abkürzung für print).
Nun zu einer python
Antwort:
Von der Kommandozeile:
$ 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
Von stdin:
$ python -c "s=input().split(); print(' '.join(j for i in zip(s,s)for j in i));" <<<"dog cat bird whale"
Das Ergebnis in beiden Fällen:
dog dog cat cat bird bird whale whale
Ein anderer Ansatz, bei dem auch nur Bash-Builtins verwendet werden
$ 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
Ich sehe keine Vorteile im Vergleich zur Top-Antwort, nur um einen etwas anderen Weg zu zeigen, der für manche Zwecke besser geeignet sein könnte.
echo
ist auch eine in Bash eingebaute Shell (Test type echo
).