Баш-сценарій, щоб повторити кожне слово в рядку?


13

У мене є такий рядок, як: dog cat bird whale

І я хочу отримати dog dog cat cat bird bird whale whale

Усі слова знаходяться в одному рядку. Будь-яка ідея?

Відповіді:


28

Додавання до сімейства рішень :-).

duplicator.sh:

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

Зробіть виконуваним і тепер:

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

Як варіант оболонки, наприклад, для повторного використання в сценарії:

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

який можна запустити безпосередньо там, де визначено як

duplicator dog cat bird whale

4
Мені подобається простота підходу до оболонки.
Хенк Лангевельд

Ну я дуже люблю простоту цього рішення
Крістіан

Шлях краще, ніж перші два способи, про які я думав.
Джо

21

Ви можете використовувати sed:

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

Якщо ви хочете зберегти зміни у файлі на місці, скажіть:

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

Ви також можете використовувати perl:

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

(Додати -iопцію для збереження змін у файлі на місці.)

Або, як пропонує тердон :

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

Цитуючи perlvar:

@F

Масив @Fмістить поля кожного рядка, зчитуваного при включенні режиму автоспліт. Дивіться perlrun для -aвимикача. Цей масив є специфічним для пакета, і йому потрібно оголосити або надати повне ім'я пакета, якщо він не є основним пакетом під час роботи під strict 'vars'.


4
Коротше: sed -r 's/\S+/& &/g'.
cYrus

2
Це не сценарій Баша. Викликати якусь команду (навіть із оболонки Bash) не складається із сценарію Bash.
Пітер Мортенсен

4
@PeterMortensen Ви технічно правильні (найкращий тип правильних), але практично кожна система, на якій встановлений bash, також матиме стандартні інструменти unix, включаючи sed і awk. Вся точка сценарію оболонки (ну, значна частина її точки) полягає в тому, щоб вказувати команди в потрібному місці.
злий

3
@PeterMortensen Це неправильно. Сценарій bash може викликати зовнішні команди. Баш сценарій повинен починатися з рядка shebang, але це не обов'язково. Питання не вказувало, що скрипт bash не повинен викликати зовнішні команди (часто його називають "чистим скриптом bash").
Жил 'ТАК - перестань бути злим'

2
Хороший трюк з перлом. Ви можете скоротити його -a:perl -M5.10.0 -ane 'say join " ", map{$_, $_} @F;'
Тердон

4

Що це було б без awk/gawkвідповіді:

$ 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 

Якщо важливий завершальний новий рядок:

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

Моє перше голосування. Просто цікаво, чому? Чи щось не так із сценарієм? Або більш скорочений варіант?
user19087

Не мій внесок, але for(i=1;i<=NF;++i) printf "%s %s ",$i,$i;ІМХО коротший і легший для читання.
rici

Важко з цим посперечатися, тому я спростив і скоротив свою відповідь (зараз використовую переваги округлення індексів до ints), не змінюючи підходу. Сподіваємось, це тепер зрозуміліше.
user19087

1
Це не сценарій Баша. Викликати якусь команду (навіть із оболонки Bash) не складається із сценарію Bash.
Пітер Мортенсен

Вкладення цього сценарію є банальним.
Кевін

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
Я думав над написанням sed -n 'p;p'- я вважав, що це прозоріше щодо того, що це робиться.
glenn jackman

1
Ви повинні додати це до відповіді!
тердон

1

Якщо у вас є рядок у змінній, скажімо foo="dog cat bird whale", ви можете зробити:

  • Чистий баш:

    $ echo "$foo" | (read a b c d && echo "$a $a $b $b $c $c $d $d")
    dog dog cat cat bird bird whale whale

    Пояснення: Дужки необхідні , так що readі echoвідбувається в тому ж подоболочки і , отже , можуть спільно використовувати змінні. Без них echoпросто надрукували б порожній рядок.

  • основні:

    $ 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

    Пояснення:-o прапор joinдозволяє встановити формат виведення. Тут я говорю це надрукувати 1-е поле 1-го файлу ( 1.1), а потім 2-е поле 1-го файлу ( 1.2) тощо. Таким чином, кожне поле 1-го файлу друкується двічі. Однак joinпризначений для об'єднання двох вхідних рядків у загальному полі. Отже, я також передаю йому порожній рядок ( <(echo)), а потім ігнорую його. У -jнаборах З'єднати поле, встановивши його на той , який не існує (5 - й) призводить joinдо друку всієї лінії.

    Якщо вам не байдуже пробіл або порядок введення, ви можете зробити це

    $ 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

    Пояснення:

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

    Сценарій, наведений вище, збереже кожне поле (з @F) двічі в масиві @kі потім надрукує @k. Якщо вам не потрібен новий рядок, ви можете спростити його

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

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

    Пояснення:-0 опція встановлює вхідний роздільник записів (як шістнадцяткове або вісімкове число, см тут для перетворення). Тут я встановлюю його на восьмикутник, 040який є пробілом. В -pмарці perlдрук кожного входу «лінія» і з тих пір ми встановили роздільник в простір, лінії тепер визначаються пробілами, тому кожне поле друкуються двічі.

  • awk:

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

    Пояснення: NF це кількість полів, тому сценарій вище проходить через кожне поле і додає його до себе. Після цього ми друкуємо рядок ( 1;це просто скорочення для друку).


0

Тепер для pythonвідповіді:

З командного рядка:

$ 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:

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

Результат в обох випадках:

dog dog cat cat bird bird whale whale

0

Трохи зверху, але haskellвідповідь:

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

0

Інший підхід, який також використовує лише 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

Я не бачу жодних переваг порівняно з головною відповіддю, просто щоб показати дещо інший спосіб, який може бути краще підходить для деяких цілей.


echoтакож оболонка, вбудована в Bash (тест type echo).
Даніель Андерссон

@DanielAndersson: Звичайно, саме тому я написав " також використовуючи лише bash вбудовані", маючи на увазі вашу приємну (вже поставлену +1) відповідь.
mpy

Гаразд, ви можете класифікувати мій коментар як сплутаність мови :-).
Даніель Андерссон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.