Bir satırdaki her kelimeyi tekrarlamak için Bash Script?


13

Gibi bir dize var: dog cat bird whale

Ve ben almak istiyorum dog dog cat cat bird bird whale whale

Tüm kelimeler aynı satırda. Herhangi bir fikir?

Yanıtlar:


28

Çözüm ailesine ekleme :-).

duplicator.sh:

for i; do echo -n "$i $i "; done; echo

Çalıştırılabilir yapın ve şimdi:

$ ./duplicator.sh dog cat bird whale
dog dog cat cat bird bird whale whale

Alternatif olarak kabuk işlevi olarak, örneğin bir komut dosyasında yeniden kullanılabilir olmak için:

duplicator() {
    for i; do echo -n "$i $i "; done; echo
}

ve daha sonra doğrudan

duplicator dog cat bird whale

4
Kabuk yaklaşımının sadeliğini seviyorum.
Henk Langeveld

Bu çözümün sadeliğini gerçekten çok seviyorum
Cristian

Düşündüğüm ilk birkaç yoldan çok daha iyi.
Joe

21

Şunları kullanabilirsiniz sed:

sed -r 's/(\S+)/\1 \1/g' filename

Dosyadaki değişiklikleri yerinde kaydetmek istiyorsanız şunu söyleyin:

sed -i -r 's/(\S+)/\1 \1/g' filename

Ayrıca perlşunları kullanabilirsiniz :

perl -M5.10.0 -ne 'say join " ", map{$_, $_} split " ";' filename

( -iDeğişiklikleri yerinde kaydetme seçeneğini ekleyin .)

Veya terdon tarafından önerildiği gibi :

perl -M5.10.0 -ane 'say join " ", map{$_, $_} @F;' filename

Alıntı perlvar:

@F

Dizi @F, otomatik bölme modu açıldığında okunan her satırın alanlarını içerir. Anahtar için bkz. Perlrun -a. Bu dizi pakete özgüdür ve altında çalıştırılırken ana pakette değilse bildirilmeli veya tam bir paket adı verilmelidir strict 'vars'.


4
Daha kısa: sed -r 's/\S+/& &/g'.
cYrus

2
Bu bir Bash betiği değil. Bazı komutları çağırmak (bir Bash kabuğundan bile) bir Bash betiği içermez.
Peter Mortensen

4
@PeterMortensen Teknik olarak haklısınız (en iyi tür), ancak pratikte bash yüklü her sistem sed ve awk dahil olmak üzere standart unix araçlarına sahip olacak. Kabuk betiğinin bütün noktası (noktanın büyük bir kısmı) komutları doğru yere işaret etmektir.
evilsoup

3
@PeterMortensen Bu yanlış. Bir bash betiği harici komutları çağırabilir. Bir bash betiği bir shebang satırıyla başlamalıdır, ancak bu kesinlikle gerekli değildir. Soru, bash betiğinin harici komutları (genellikle "saf bash betiği" olarak adlandırılır) çağırmaması gerektiğini belirtmedi.
Gilles 'SO- kötü olmayı bırak'

2
Güzel perl hilesi. -aperl -M5.10.0 -ane 'say join " ", map{$_, $_} @F;'
Şununla

4

awk/gawkCevap olmadan bu ne olurdu :

$ 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 

Sonlandırıcı bir yeni satır önemliyse:

$ awk '{ for(i=1;i<=NF+1;i+=1/2) { printf("%s ",$i); }} END{print ""}' <<<"dog cat bird whale"

Benim ilklerim oy. Sadece merak ediyorum, neden? Senaryoda yanlış bir şey mi var? Yoksa daha kısaltılmış bir versiyon mu?
user19087

Benim oyum değil, ama for(i=1;i<=NF;++i) printf "%s %s ",$i,$i;hem daha kısa hem de daha okunabilir IMHO.
rici

Bununla tartışmak zor, bu yüzden yaklaşımı değiştirmeden cevabımı basitleştirdim ve kısalttım (şimdi indekslerin ints'a yuvarlanmasından yararlanıyor). Umarım şimdi daha açıktır.
user19087

1
Bu bir Bash betiği değil. Bazı komutları çağırmak (bir Bash kabuğundan bile) bir Bash betiği içermez.
Peter Mortensen

Ancak bunu bir senaryoya koymak önemsizdir.
Kevin

3
s="dog cat bird wale"
ss=$( tr ' ' '\n' <<< "$s" | sed p | tr '\n' ' ' )
echo "$ss"
dog dog cat cat bird bird wale wale 

1
Yazmayı düşündüm sed -n 'p;p'- bunun ne yaptığı hakkında daha şeffaf olduğunu düşündüm.
glenn jackman

1
Bunu cevaba eklemelisin!
terdon

1

Dizginizi bir a değişkeninde foo="dog cat bird whale"varsa, şunları yapabilirsiniz:

  • Saf 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

    Açıklama: parantez böylece ihtiyaç vardır readve echoaynı alt kabukta meydana makta ve böylece hisse değişkenleri. Onlar olmadan, echosadece boş bir satır yazdırırdı.

  • 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

    Açıklama:-o bayrağı joinçıkış biçimini ayarlamak için izin verir. Burada, 1. dosyanın ( 1.1) 1. alanını, ardından 1. dosyanın 2. alanını ( 1.2) vb . Yazdırmasını söylüyorum . Böylece 1. dosyanın her alanı iki kez yazdırılır. Bununla birlikte, ortak bir alanda iki giriş hattını joinbirleştirmek için tasarlanmıştır . Ben de boş bir çizgi ( ) geçip görmezden geliyorum . Birleştirme alanını ayarlar ve var olmayan bir alana ayarlar (5.) tüm satırın yazdırılmasına neden olur .<(echo)-jjoin

    Boşluk veya giriş sırası ile ilgilenmiyorsanız,

    $ 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

    Açıklama:

    -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.

    Yukarıdaki komut dizisi her alanı @Fdiziden iki kez kaydedip @kyazdırır @k. Sondaki satırsonuna ihtiyacınız yoksa,

    $ echo $foo | perl -ane 'print " $_ $_" for @F'
  • Perl 2:

    $ echo $foo | perl -0040 -pne 'print "$_"' | paste - - 
    dog dog cat cat bird bird whale whale

    Açıklama: Bu -0seçenek giriş kayıt ayırıcısını ayarlar (onaltılık veya sekizli sayı olarak, dönüşümler için buraya bakın ). Burada, 040bir boşluk olan sekizlik olarak ayarlıyorum . -pMarkaları perlher girdi "çizgi" yazdırmak ve uzaya rekor ayırıcı belirledik beri her alan iki defa basılır, böylece çizgiler artık boşluklarla tanımlanır.

  • awk:

    $ echo $foo | awk '{for(i=1;i<=NF;i++){$i=$i" "$i;} 1;}'
    dog dog cat cat bird bird whale whale

    Açıklama: NF alan sayısıdır, bu nedenle yukarıdaki komut dosyası her bir alandan geçer ve kendisine eklenir. Bu yapıldıktan sonra, çizgiyi yazdırırız ( 1;sadece yazdırma için kısayol).


0

Şimdi bir pythoncevap için:

Komut satırından:

$ 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

Stdin'den:

$ python -c "s=input().split(); print(' '.join(j for i in zip(s,s)for j in i));" <<<"dog cat bird whale"

Her iki durumda da sonuç:

dog dog cat cat bird bird whale whale

0

Biraz üstten, ama bir haskellcevap:

$ ghc -e "getLine >>= putStrLn . unwords . (concatMap $ replicate 2) . words" <<<"dog cat bird whale"
dog dog cat cat bird bird whale whale

0

Başka bir yaklaşım, sadece bash yerleşkelerini kullanarak

$ 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

En iyi cevaba kıyasla hiçbir fayda görmüyorum, sadece biraz farklı bir yol göstermek için, bazı amaçlar için daha uygun olabilir.


echoaynı zamanda Bash (test type echo) 'te bulunan bir mermidir .
Daniel Andersson

@DanielAndersson: Elbette, bu yüzden güzel (zaten + 1'lenmiş) cevabınızı alarak "sadece bash yerleşiklerini de kullanarak " yazdım .
mpy

Tamam, yorumumu dil karmaşası olarak sınıflandırabilirsiniz :-).
Daniel Andersson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.