Réponses:
Ajout à la famille de solutions :-).
duplicator.sh
:
for i; do echo -n "$i $i "; done; echo
Rendez exécutable, et maintenant:
$ ./duplicator.sh dog cat bird whale
dog dog cat cat bird bird whale whale
Alternativement comme fonction shell, par exemple pour être réutilisable dans un script:
duplicator() {
for i; do echo -n "$i $i "; done; echo
}
qui peut ensuite être exécuté directement là où il est défini comme
duplicator dog cat bird whale
Vous pouvez utiliser sed
:
sed -r 's/(\S+)/\1 \1/g' filename
Si vous souhaitez enregistrer les modifications apportées au fichier sur place, dites:
sed -i -r 's/(\S+)/\1 \1/g' filename
Vous pouvez également utiliser perl
:
perl -M5.10.0 -ne 'say join " ", map{$_, $_} split " ";' filename
(Ajoutez l' -i
option pour enregistrer les modifications apportées au fichier sur place.)
Ou, comme l'a suggéré terdon :
perl -M5.10.0 -ane 'say join " ", map{$_, $_} @F;' filename
Citant de perlvar
:
@F
Le tableau
@F
contient les champs de chaque ligne lue lorsque le mode de séparation automatique est activé. Voir perlrun pour le-a
commutateur. Ce tableau est spécifique au package et doit être déclaré ou donné un nom de package complet s'il n'est pas dans le package principal lors de l'exécution sousstrict 'vars'
.
sed -r 's/\S+/& &/g'
.
-a
:perl -M5.10.0 -ane 'say join " ", map{$_, $_} @F;'
Que serait-ce sans awk/gawk
réponse:
$ 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
Si une nouvelle ligne de terminaison est 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;
est à la fois plus court et plus lisible, à mon humble avis .
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'
- je pensais que c'était plus transparent sur ce qu'il faisait.
Si vous avez votre chaîne dans une variable, disons foo="dog cat bird whale"
, vous pouvez faire:
Bash pur:
$ echo "$foo" | (read a b c d && echo "$a $a $b $b $c $c $d $d")
dog dog cat cat bird bird whale whale
Explication: Les parenthèses sont nécessaires pour que le read
et echo
se produisent dans le même sous-shell et peuvent donc partager des variables. Sans eux, le echo
serait simplement imprimer une ligne vierge.
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
Explication: Le -o
drapeau de join
vous permet de définir le format de sortie. Ici, je lui dis d'imprimer le 1er champ du 1er fichier ( 1.1
), suivi du 2ème champ du 1er fichier ( 1.2
) etc. De cette façon, chaque champ du 1er fichier est imprimé deux fois. Cependant, join
est conçu pour, bien, joindre deux lignes d'entrée sur un champ commun. Donc, je lui passe également une ligne vide ( <(echo)
), puis je l'ignore. Le -j
définit le champ de jointure, en le définissant sur un champ qui n'existe pas (le 5e) provoque l' join
impression de la ligne entière.
Si vous ne vous souciez pas des espaces ou de l'ordre d'entrée, vous pouvez le faire
$ 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
Explication:
-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.
Le script ci-dessus enregistre chaque champ (de @F
) deux fois dans le tableau @k
, puis l'imprime @k
. Si vous n'avez pas besoin de la nouvelle ligne de fin, vous pouvez simplifier
$ echo $foo | perl -ane 'print " $_ $_" for @F'
Perl 2:
$ echo $foo | perl -0040 -pne 'print "$_"' | paste - -
dog dog cat cat bird bird whale whale
Explication: L' -0
option définit le séparateur d'enregistrement d'entrée (sous forme de nombre hexadécimal ou octal, voir ici pour les conversions). Ici, je le mets à octal 040
qui est un espace. Les -p
marques perl
impriment chaque "ligne" d'entrée et puisque nous avons défini le séparateur d'enregistrement sur espace, les lignes sont maintenant définies par des espaces, donc chaque champ est imprimé deux fois.
awk
:
$ echo $foo | awk '{for(i=1;i<=NF;i++){$i=$i" "$i;} 1;}'
dog dog cat cat bird bird whale whale
Explication: NF
est le nombre de champs, donc le script ci-dessus passe par chaque champ et l'ajoute à lui-même. Une fois cela fait, nous imprimons la ligne ( 1;
c'est juste un raccourci pour l'impression).
Maintenant pour une python
réponse:
Depuis la ligne de commande:
$ 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
Depuis stdin:
$ python -c "s=input().split(); print(' '.join(j for i in zip(s,s)for j in i));" <<<"dog cat bird whale"
Le résultat dans les deux cas:
dog dog cat cat bird bird whale whale
Une autre approche, utilisant également uniquement les builds 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
Je ne vois aucun avantage par rapport à la première réponse, juste pour montrer une manière légèrement différente, qui pourrait être mieux adaptée à certaines fins.
echo
est également un shell intégré à Bash (test type echo
).