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?


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

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}

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}

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ść

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


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.


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.


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ść

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

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!


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

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

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.


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'

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


1

Spróbuj tego:

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

Stworzy (sto myślników):


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.