Polecenie Linux, aby powtórzyć ciąg n razy

71

Czy jest jakieś wbudowane polecenie Linuksa, które pozwala wyprowadzić ciąg, który jest n razy ciągiem wejściowym?

Uwolnić się
źródło
1
Przez „wbudowane polecenie linux” zakładam, że masz na myśli polecenie powłoki, a ponieważ nie wspominasz o używanej powłoce, zakładam, że to bash. Możesz to sprawdzić, wpisując „echo $ SHELL” w wierszu poleceń i powinieneś otrzymać coś podobnego do „/ bin / bash”. Jeśli nie, powinieneś edytować swoją odpowiedź, aby określić, co ma pokazywać. Na zdrowie :)
Adrian Petrescu,
7
Oznacziłem pytanie słowem „bash”. Myślałem, że to wystarczy.
GetFree,

Odpowiedzi:

75
adrian@Fourier:~$ printf 'HelloWorld\n%.0s' {1..5}
HelloWorld
HelloWorld
HelloWorld
HelloWorld
HelloWorld
adrian@Fourier:~$
Adrian Petrescu
źródło
3
Czy możesz wyjaśnić, jak to działa? Rozumiem polecenie printf, ponieważ jest ono takie samo, jak w C / C ++. Ale nie rozumiem, jak rozwinięto {1..5} i jak to działa w połączeniu z częścią „% .0s”.
GetFree,
4
To trochę włamanie :) Spróbuj uruchomić „printf 'HelloWorld% d \ n' 1 2 3 4 5” i prawdopodobnie kliknie za ciebie. Flaga% .0s nic nie robi, po prostu zbieraj argumenty. Następnie, jeśli bash otrzyma więcej argumentów niż specyfikatory formatu, po prostu wydrukuje wiele kopii, chwytając tyle, ile potrzebuje. Więc dostajesz efekt. Wynik „printf” HelloWorld% d% d \ n '1 2 3 4 5 6 ”prawdopodobnie czyni go jeszcze wyraźniejszym. Mam nadzieję że to pomoże!
Adrian Petrescu
Widzę. To szczególne zachowanie printf pozwala na powtórzenie
GetFree
1
(Powinienem zauważyć, że z czysto teoretycznego punktu widzenia jest to prawdopodobnie najszybsze rozwiązanie, ponieważ używa pojedynczej powłoki pierwotnej - nie żadnych procesów zewnętrznych. W rzeczywistości, spójrzmy prawdzie w oczy, wydajność skryptów bash nie ma tak naprawdę znaczenia: )
Adrian Petrescu
1
Co jest charakterystyczne dla printfjest to, że wielokrotnie zastosować nadmiar argumenty ciąg Format „pętli” za darmo. Przez „nadmiar” rozumiem, że jest więcej argumentów niż %symboli zastępczych.
Dennis Williamson,
69

Oto staromodny sposób, który jest dość przenośny:

yes "HelloWorld" | head -n 10

To jest bardziej konwencjonalna wersja odpowiedzi Adriana Petrescu z użyciem rozszerzenia nawiasów klamrowych:

for i in {1..5}
do
    echo "HelloWorld"
done

Odpowiada to:

for i in 1 2 3 4 5

To jest nieco bardziej zwięzła i dynamiczna wersja odpowiedzi szczupaka :

printf -v spaces '%*s' 10 ''; printf '%s\n' ${spaces// /ten}
Dennis Williamson
źródło
Jak pozbyć się nowych linii, używając polecenia tak?
GetFree,
3
Jednym ze sposobów jest przepuszczenie go przez rurkę sed -n 'H;${x;s/\n//gp}'lub sed -n ':t;${s/\n//gp};N;bt'innym, echo $(yes "HelloWorld" | head -n 10)co powoduje dodanie spacji między każdą kopią ciągu. Jeszcze innym sposobem jest przepuszczenie go, tr -d '\n'co również eliminuje końcową nową linię.
Dennis Williamson,
2
To jest jak Haskell w bash shell: Hashell?
wchargin
4
Tak, rozwiązanie jest całkiem
fajne
yesRozwiązaniem było dokładnie to, co potrzebne, ponieważ chciałem powielać polecenie (którego moc waha). Tak więc:yes "$(my-command)" | head -n 2
arnsholt
14

Można to sparametryzować i nie wymaga zmiennej temp, FWIW:

printf "%${N}s" | sed 's/ /blah/g'

Lub jeśli $Njest wielkości tablicy bash:

echo ${ARR[@]/*/blah}
twifkak
źródło
3
Jest to najkrótsza POSIX 7 rozwiązanie widziałem tak daleko od seq, yesi {1..5}nie są POSIX 7.
Ciro Santilli新疆改造中心法轮功六四事件
Nie należy mieszać danych ze printfspecyfikatorem formatu. Co jeśli dane zawierają ciągi formatujące? Jest to właściwy sposób na dynamiczne określenie „precyzji” (długości): printf '%*s' "$N"- nawyk umieszczania ciągu formatu w pojedynczych cudzysłowach, aby zapobiec rozszerzaniu się zmiennych.
Dennis Williamson
13

Wymieniono już kilka dobrych sposobów. Nie można jednak zapomnieć o starym dobrym seq:

[John @ awesome] $ dla i w `seq 5`; wykonaj echo „Cześć”; gotowe
cześć
cześć
cześć
cześć
cześć
John T.
źródło
Ten faktycznie szanuje zero, traktując je jako zero! ( {i..j}Sztuczka nigdy nie zwraca pustego zakresu.)
JellicleCat
10

Być może inny sposób, który jest bardziej ogólny i przydatny dla Ciebie:

adrian@Fourier:~$ n=5
adrian@Fourier:~$ for (( c=1; c<=n; c++)) ; do echo "HelloWorld" ; done
HelloWorld
HelloWorld
HelloWorld
HelloWorld
HelloWorld
adrian@Fourier:~$ 

Powłoka bash jest silniejsza niż myśli większość ludzi :)

Adrian Petrescu
źródło
To zyskuje mój głos, ponieważ jest całkowicie wewnętrzny; nie wymaga rozwidlenia.
esm
2
Do jakiego rozwidlenia się odnosisz? Oryginalna odpowiedź nie wymaga żadnej. Wyjściem „type printf” jest „printf to wbudowana powłoka” i dlatego działa w ramach oryginalnego procesu bash.
CodeGnome
Jest to jedyny jak dotąd ( yes, printf, for i in {1..5}), że jeśli njest zero, zwraca pusty ciąg bez istnieć stan 1. Również ze względu na notacji matematycznej dla porównania, jest to łatwe do przesunięcia o 1 (np zmieniając <=się <)
Mehrad Mahmoudian
10

Możesz użyć lewy. Wyszukanie pustej zmiennej nic nie drukuje. Możesz więc napisać:

echo word$wojek{1..100}

Jeśli $wojek1 $wojek2... $wojek100nieistniejące zmienne, twoje słowo zostanie powtórzone 100 razy bez niczego innego.

Wojciech Waga
źródło
1
To brzydki brzydki hack, a jednak nie mogę się powstrzymać, ale uwielbiam go i używam.
16807
Kocham to! Może użycie $_zamiast $wojeksprawia, że ​​zamiar jest jaśniejszy.
Mihai Todor
7

Powtórz nczasy, po prostu wstaw n-1przecinki między {}:

$ echo 'helloworld'{,,}
helloworld helloworld helloworld

Powtarza „helloworld” dwa razy po pierwszym echu.

kev
źródło
5
Fajnie, ale co jeśli chcę uzyskać nzmienną?
GetFree
1
dodaje dodatkowe miejsce po każdym „helloworld”
PADYMKO
wydaje się, że nie pozwala to również na umieszczanie nowych wierszy w łańcuchu (tj. uzyskiwanie helloworld na własnych liniach)
TankorSmash
5
awk 'BEGIN {while (c++<4) printf "Hello"}'

Wynik

Cześć cześć cześć cześć
Steven Penny
źródło
Użyj tego bez awk: while ((c ++ <5)); zrób printf 'hello'; gotowe
emf
4

Z rozwiązaniem spotkałem się z ostrzeżeniami o uszkodzonej rurze yes, więc oto kolejna dobra alternatywa:

$ seq 4 | sed "c foo"
foo
foo
foo
foo
n.caillou
źródło
3

na podstawie tego, na co wskazywał @pike

dla każdego znaku w ciągu ciąg echa

echo ${target//?/$replace}

Przykład nagłówka podkreślonego =znakami

export heading='ABCDEF'; 
export replace='='; 
echo -e "${heading}\n${heading//?/$replace}"

wyjdzie

ABCDEF
======

Wydaje się, że jest to port pomiędzy Linuksem a OS X i to mnie cieszy.

nJoy!

nikiel
źródło
3

Jeśli korzystasz z BSD, możesz po prostu użyć seq.

$ seq -f "Hello, world" 5
Hello, world
Hello, world
Hello, world
Hello, world
Hello, world
Qix
źródło
1
W seq (GNU coreutils) 8.25daje to seq: format 'Hello, world' has no % directive, wymuszając obecność dyrektywy formatującej. Coreutils GNU są używane np. W wielu dystrybucjach Linuksa i Cygwin. W tym informacje dla tych, którym brakuje informacji, że działa tylko w sekwencji BSD.
Palec,
2
line="==========================="
line=${line:0:10}
${line//"="/"ten "}

wyjścia

ten ten ten ten ten ten ten ten ten ten
pospolity
źródło
Może bardziej szczegółowy przykład: deklaruj c = '-----'; c = $ {c // $ {c: 0: 1} / $ c}; echo $ c # Drukuje "-" 25 razy.
Stephen Niedzielski
2

Zakładając, że potrzebujesz czegoś takiego jak xoperator Perla , w którym nie otrzymujesz automatycznie nowej linii między powtórzeniami:

x() {
  # usage: x string num
  for i in $(seq 1 $2); do printf "%s" "$1"; done
  # print a newline only if the string does not end in a newline
  [[ "$1" == "${1%$'\n'}" ]] && echo ""
}

x Hi 10  # ==> HiHiHiHiHiHiHiHiHiHi

x $'Hello World!\n' 3

Jawnie użyłem forpętli, ponieważ nie można pisać {1..$n}bash: interpretacja nawiasów jest wykonywana przed podstawieniem zmiennej.

Glenn Jackman
źródło
2

Nie do końca wbudowany w Linuksa, ale jeśli masz zainstalowany Python ...

python
>>>var = "string"
>>>var*n

Lub w jednym wierszu, jak sugerował komentator:

python -c 'print "This is a test.\n" * 10'
eqzx
źródło
4
Niezbyt przydatne, ponieważ nie można go łatwo zintegrować ze skryptami powłoki itp. A ponieważ istnieje około miliarda sposobów na wykonanie tego w samej powłoce, nie widzę powodu, aby wyciągać za to duże pistolety (tj. Python) .
Adrian Petrescu
7
Zgadzam się z twoim drugim punktem, ale nie z pięścią ... łatwo jest zintegrować ze skryptem powłoki: python -c 'print "To jest test. \ N" * 10'
larsks
Podoba mi się czytelność tego rozwiązania, co jest dla mnie wystarczającym powodem. ;)
elias
2

Brak magii tutaj:

seq 5 | awk '{print "Hello World"}'

brablc
źródło
1

Spróbuj tego:

echo $(for i in $(seq 1 100); do printf "-"; done)

Stworzy (sto myślników):


Alle Aldine
źródło