У меня есть строка вроде:dog cat bird whale
И я хочу получитьdog dog cat cat bird bird whale whale
Все слова в одной строке. Есть идеи?
решение1
Пополнение в семействе решений :-) .
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
решение2
Вы можете использовать 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
. Этот массив зависит от пакета и должен быть объявлен или ему должно быть дано полное имя пакета, если он не находится в package main при запуске подstrict 'vars'
.
решение3
Что бы это было без 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"
решение4
Если у вас есть строка в переменной, скажем 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
просто вывел бы пустую строку.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
Объяснение:Флаг
-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
Перл 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'
Перл 2:
$ echo $foo | perl -0040 -pne 'print "$_"' | paste - - dog dog cat cat bird bird whale whale
Объяснение:Опция
-0
устанавливает разделитель входных записей (в виде шестнадцатеричного или восьмеричного числа, см.здесьдля преобразований). Здесь я устанавливаю его на восьмеричное,040
что является пробелом.-p
Makesperl
печатает каждую входную «строку», и поскольку мы установили разделитель записей на пробел, строки теперь определяются пробелами, поэтому каждое поле печатается дважды.awk
:$ echo $foo | awk '{for(i=1;i<=NF;i++){$i=$i" "$i;} 1;}' dog dog cat cat bird bird whale whale
Объяснение:
NF
это количество полей, поэтому скрипт выше проходит по каждому полю и добавляет его к себе. После этого мы печатаем строку (1;
это просто сокращение для print).