2011-04-27 12 views

Odpowiedz

29

pewien, wystarczy użyć printf i trochę manipulacji bash ciąg

$ s=$(printf "%-30s" "*") 
$ echo "${s// /*}" 
****************************** 

Nie powinno być krótsza droga, ale obecnie to jak chciałbym to zrobić. Można zrobić to do funkcji, które można przechowywać w bibliotece do przyszłego wykorzystania

printf_new() { 
str=$1 
num=$2 
v=$(printf "%-${num}s" "$str") 
echo "${v// /*}" 
} 

próbny:

$ printf_new "*" 20 
******************** 
$ printf_new "*" 10 
********** 
$ printf_new "%" 10 
%%%%%%%%%% 
+2

Możesz uniknąć podpowłoki tutaj, jeśli używasz 'printf -v'. 'printf -v str '% -30s' ''; echo "$ {str ///*}" ' – kojiro

+1

-1. Jest to bardzo powolne, szczególnie dla> 1000 znaków. Prawie wszystko jest szybsze, w tym 'printf '% .s *' {1..30}' lub 'printf '% * s' 1000000 '' | tr '' '*'' dla dużych liczb. – Deadcode

+1

Błąd printf_new kończy się podczas trzeciego uruchomienia testowego. Naprawię to tak: 'printf -v v"% - * s "" $ num "" "; echo "$ {v ///$ str}" '' – jarno

2

To brzydki, ale można to zrobić tak:

$ for a in `seq 5`; do echo -n %; done 
%%%%% 

oczywiście seq jest zewnętrznym pro gram (który prawdopodobnie masz).

+2

Po co używać innego programu, kiedy można po prostu napisać: 'dla a in {1..5}; do echo -n%; done'.) –

+1

Wyobraziłem sobie, że w scenariuszu moje "rozwiązanie" nie działa, oto gotowe rozwiązanie. –

+0

-1. Jest wolniejszy od 'printf"% 0.s %% "{1..5}', który z kolei jest wolniejszy niż 'printf '% * s' 5 '' | tr '' '%''. – Deadcode

7

Lubię to:

echo $(yes % | head -n3) 

Nie możesz słuszne:

for ((i=0; i<3; i++)){ 
    echo -ne "%" 
} 

Możecie słuszne:

s=$(printf "%3s"); echo " ${s// /%}" 

Źródło: http://dbaspot.com/shell/357767-bash-fast-way-repeat-string.html

Istnieje również to forma, ale nie bardzo przydatne:

echo %{,,} 
+5

+1 dla kombinacji 'tak' i' głowa' – fmark

+0

Właśnie tego ludzie używają teraz! Szukałem '/ dev/y' i nie mogłem go znaleźć w moim nowoczesnym systemie. –

0

inny:

char='%' 
count=5 
result=$(printf "%${count}s" ' ') 
echo -e ${result// /$char} 
1
  1. Jest możliwe aby uzyskać dowolną liczbę znaków zero (\0) z /dev/zero. Jedyną rzeczą do zrobienia Jest

    head -c 20 /dev/zero |tr '\0' '+' 
    

    Zauważ, że head i tr są polecenia zewnętrzne. Aby był on wywoływany w oddzielnym procesie.

  2. Możliwe jest "optymalizowanie" tego rozwiązania za pomocą buforowania ciągów znaków.

    CACHE="$(head -c 1000 /dev/zero |tr '\0' '+')" 
    echo "${CACHE:0:10}" 
    echo "${CACHE:0:100}" 
    echo "${CACHE:0:300}" 
    

    Tylko wbudowane są bash w instrukcji echa. Możemy więc użyć go w cyklu.

+1

To nie działa; przechodzi w niekończącą się pętlę, wysyłając nieograniczoną liczbę znaków, a nie 20 zgodnie z przeznaczeniem. Prawidłowe polecenie to 'head -c 20/dev/zero | tr '\ 0' '+''. – Deadcode

+0

Wygląda to na literówkę na części ssvda. Powinien to być 'head -c 20', aby wydrukować pierwszych 20 znaków. 'head -n 20' wyświetla pierwsze 20 linii. – Six

89

Jest rzeczywiście jedno-liner, że może to zrobić:

printf "%0.s-" {1..10} 

drukuje

---------- 

Oto podział argumentów przekazanych do printf:

  • % s - Określa ciąg o dowolnej długości
  • % 0s - określa ciąg zerowej długości, lecz jeśli argument jest już zostanie wydrukowana cała sprawa
  • % 0.s - To samo co powyżej, ale okres opowiada printf obciąć ciąg jeśli jest dłuższy niż podana długość, to jest zero
  • {1..10} - To rozszerzenie nawiasu, które faktycznie przekazuje argumenty "1 2 3 4 5 6 7 8 9 10"
  • "-" - Jest to dodatkowy znak dostarczony do printf, może to być cokolwiek (dla "%" musisz najpierw uciec z innym "%", np. "%%")
  • Wreszcie, domyślne zachowanie dla printf, jeśli podaj więcej argumentów, niż podano w łańcuchu formatów, aby powrócić do początku ciągu formatu i uruchomić go ponownie.

Końcowym rezultatem tego, co się tutaj dzieje, jest to, że mówisz printf, że chcesz wydrukować łańcuch o zerowej długości bez dodatkowych znaków, jeśli podany łańcuch jest dłuższy niż zero. Następnie po tym łańcuchu o zerowej długości wydrukuj "-" (lub jakikolwiek inny zestaw znaków). Następnie podajesz 10 argumentów, więc drukuje 10 ciągów o zerowej długości po każdym z nich za pomocą "-".

To jednolinijka, która drukuje dowolną liczbę powtarzających się znaków!

Edit:

Przypadkowo, jeśli chcesz wydrukować $variable znaków po prostu trzeba zmienić argument nieznacznie używać seq zamiast interpretacji nawiasów w następujący sposób:

printf '%0.s-' $(seq 1 $variable) 

Będzie to zamiast przekazywać argumenty " 1 2 3 4 ... $ zmienna "do printf, precyzyjne drukowanie $variable wystąpień" - "

+4

Bardzo dobrze, ale to nie działa w *** #!/Bin/sh ***, ale tylko w *** #!/Bin/bash *** –

+0

Ponieważ to używa wbudowanego basha, dla małej liczby powtarzające się znaki powinny być szybsze niż metody zewnętrznych procesów spawnu. W przypadku dużych liczb, 'printf '% * s' 1000000 '' | tr '' '-'' i inne metody są szybsze. – Deadcode

+0

Moje jedyne pytanie brzmi: w jakiej sytuacji chciałbyś wydrukować powtarzającą się postać milion razy? Inne operacje, które mogłem zobaczyć, ale to tylko nasyciłoby twój wynik pozornie bezsensownymi postaciami. – CaffeineConnoisseur

-1

Oto najprostszy sposób na zrobienie tego

seq -s % 4|tr -d '[:digit:]' 

Uwaga: w utworzonej sekwencji będzie tylko 3 "%".

+0

-1. Drukuje początkowy znak nowego wiersza, drukuje o jeden znak mniej niż liczba przekazana i jest wolniejszy od 'printf '% * s' 3 '' | tr '' '%''. – Deadcode

15

Aktualna zaakceptowana odpowiedź na to pytanie (przez ghostdog74) zapewnia metodę, która wykonuje bardzo wolno nawet dla umiarkowanie dużej liczby znaków. Najwyżej głosowana odpowiedź (przez CaffeineConnoisseur) jest lepsza, ale wciąż jest dość powolna.

Oto, co w moich testów, wykonał najszybszy wszystkim (nawet szybciej niż wersja Pythona):

perl -E "print '*' x 1000" 

Na drugim miejscu znalazł polecenie python:

python -c "print('*' * 1000)" 

Jeśli żadna perl i python są dostępne, to jest trzecia najlepsza:

head -c 1000 /dev/zero | tr '\0' '*' 

A na czwartym miejscu jest ten śpiewać bash printf wbudowaną wraz z tr:

printf '%*s' 1000 | tr ' ' '*' 

i tu jest jeden (od CaffeineConnoisseur „s odpowiedź), który znajduje się na piątym miejscu w prędkości dla dużej liczby powtarzających się znaków, ale może być szybsze dla małych liczb (z powodu do korzystania tylko bash wbudowany, a nie tarła proces zewnętrznego):

printf '%.s*' {1..1000} 
+0

Zakładając, że '*' jest wyprowadzanym znakiem, jaki jest cel poprzedzającego '% .s' w ostatecznym przykładzie? – Hashim

+0

"% s" jest specyfikacją formatu dla printf, po prostu oznacza ciąg. Pomiędzy "%" i "s" można ustawić atrybuty długości dla ciągu znaków. Używając "." lub ".0" ustawi maksymalną długość łańcucha na zero, nie drukując niczego dla tego ciągu. W tym przykładzie zakres jest rozszerzany do 1 2 3 4 5 ..... 98 99 100, a każda liczba jest traktowana jako ciąg o zerowej długości. W ten sposób kontrolujesz liczbę wydrukowanych gwiazdek. –

0
#!/usr/bin/awk -f 
BEGIN { 
    while (c++ < 3) printf "%" 
} 

Wynik

 
%%%