Bash에서 문자를 어떻게 반복 할 수 있습니까?


240

어떻게하면 echo됩니까?

perl -E 'say "=" x 100'

슬프게도 이것은 Bash가 아닙니다.
solidsnack

1
echo가 아니라 같은 주제 ruby -e 'puts "=" * 100'또는python -c 'print "=" * 100'
Evgeny

1
좋은 질문입니다. 아주 좋은 답변입니다. 나는 실제 작업에서 하나의 답변을 사용하여 여기에 예제로 게시 할 것입니다 : github.com/drbeco/oldfiles/blob/master/oldfiles ( printf와 함께 사용 seq)svrb=`printf '%.sv' $(seq $vrb)`
Dr Beco

줄 바꿈을 포함하여 1 개 이상의 문자를 인쇄하는 일반적인 솔루션 : Repeat_this () {i = 1; [ "$ i"-le "$ 2"]; printf "% s" "$ 1"을하십시오; i = $ (($ i + 1)); 완료; printf '\ n';}. 다음과 같이 사용하십시오 : Repeat_this "something"Number_of_repetitions. 예를 들어, 줄 바꿈 3 개를 포함하여 5 번 반복되는 쇼케이스 : Repeat_this "$ (printf '\ n \ n \ nthis')"5. 마지막 printf '\ n'이 출력 될 수 있습니다 (그러나 텍스트 파일을 만들려면 마지막 문자로 줄 바꿈이 필요합니다!)
Olivier Dulac

답변:


396

당신이 사용할 수있는:

printf '=%.0s' {1..100}

작동 원리 :

Bash는 {1..100}을 확장하므로 명령은 다음과 같습니다.

printf '=%.0s' 1 2 3 4 ... 100

printf의 형식을 설정 했습니다. 이는 주어진 인수에 관계없이 =%.0s항상 단일을 인쇄한다는 것을 의미합니다 =. 따라서 100 =초를 인쇄합니다 .


14
반복 횟수가 많더라도 합리적으로 잘 수행되는 훌륭한 솔루션입니다. 예를 들어 다음과 같이 호출 할 수있는 함수 래퍼가 있습니다 repl = 100( eval안타깝게도 변수에 중괄호 확장을 설정하려면 속임수가 필요합니다) :repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
mklement0

7
var를 사용하여 상한을 설정할 수 있습니까? 시도했지만 작동하지 않습니다.
Mike Purcell

70
중괄호 확장 내에서는 변수를 사용할 수 없습니다. seq대신 사용하십시오 ( 예 :) $(seq 1 $limit).
dogbane

11
당신이 functionalise 경우가에서 재 배열하는 것이 가장 좋습니다 $s%.0s%.0s$s, 그렇지 않으면 대시가 원인이 printf오류입니다.
KomodoDave

5
이로 인해 Bash의 동작을 알 수 printf있습니다. 인수가 남지 않을 때까지 형식 문자열을 계속 적용합니다. 형식 문자열을 한 번만 처리했다고 가정했습니다!
Jeenu

89

쉬운 방법은 없습니다. 그러나 예를 들면 다음과 같습니다.

seq -s= 100|tr -d '[:digit:]'

또는 표준 준수 방법 일 수도 있습니다.

printf %100s |tr " " "="

또한 tput rep있지만, 내 터미널 (xterm 및 Linux)은 지원하지 않는 것 같습니다.)


3
seq의 첫 번째 옵션은 주어진 수보다 적은 수를 인쇄하므로이 예에서는 99 =자를 인쇄 합니다.
Camilo Martin

13
printf tr때문에 유일한 POSIX 솔루션 seq, yes그리고 {1..3}POSIX 없습니다.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

2
단일 문자가 아닌 문자열을 반복하려면 : printf %100s | sed 's/ /abc/g'- 'abcabcabc ...'출력
John Rix

3
루프를 사용하지 않고 외부 명령을 하나만 사용하는 경우 +1입니다 ( tr). 당신은 또한 같은 것으로 확장 할 수 있습니다 printf "%${COLUMNS}s\n" | tr " " "=".
musiphil

2
@ mklement0 글쎄, 당신이 실수로 마지막 개행을 계산하기를 바랐습니다 wc. 내가 이것에서 취할 수있는 유일한 결론은 "사용 seq해서는 안된다 " 는 것입니다.
Camilo Martin

51

그의 입력 을 위해 @ gniourf_gniourf에 대한 모자의 팁 .

참고 :이 답변은 원래 질문에 대한 답변이 아니라 성능비교 하여 기존의 유용한 답변을 보완 합니다 .

솔루션은 실행 속도 측면에서만 비교됩니다. 메모리 요구 사항은 고려 되지 않습니다 (솔루션마다 다르며 반복 횟수가 큰 경우도 있습니다).

요약:

  • 귀하의 경우 반복 횟수가 적은 , 약 100, 그것의 최대 말할 가치가 함께가는 강타 전용 솔루션 시동 외부 유틸리티 문제의 비용, 특히 펄의로.
    • 당신은 단지 필요하면 실용적으로 말하기, 그러나 하나 개의 문자를 반복 인스턴스를, 기존의 모든 솔루션은 잘 될 수 있습니다.
  • 반복 횟수 , 사용 외부 유틸리티를 그들이 훨씬 더 빨리 할 것 같은.
    • 특히 큰 문자열
      (예 :)로 Bash의 전역 하위 문자열을 대체하지 마십시오 ${var// /=}. 엄청나게 느립니다.

다음은 OSX 10.10.4 및 bash 3.2.57을 실행하는 3.2GHz Intel Core i5 CPU 및 Fusion Drive가 장착 된 2012 년 말 iMac에서 수행 한 타이밍 이며 평균 1000 회 실행입니다.

항목은 다음과 같습니다

  • 실행 시간의 오름차순으로 나열 됨 (가장 빠른 것부터)
  • 접두사 :
    • M... 잠재적으로 다중 문자 솔루션
    • S... 단일 문자 전용 솔루션
    • P ... POSIX 호환 솔루션
  • 그 뒤에 솔루션에 대한 간단한 설명
  • 원래 답변의 저자 이름으로 접미사

  • 작은 반복 횟수 : 100
[M, P] printf %.s= [dogbane]:                           0.0002
[M   ] printf + bash global substr. replacement [Tim]:  0.0005
[M   ] echo -n - brace expansion loop [eugene y]:       0.0007
[M   ] echo -n - arithmetic loop [Eliah Kagan]:         0.0013
[M   ] seq -f [Sam Salisbury]:                          0.0016
[M   ] jot -b [Stefan Ludwig]:                          0.0016
[M   ] awk - $(count+1)="=" [Steven Penny (variant)]:   0.0019
[M, P] awk - while loop [Steven Penny]:                 0.0019
[S   ] printf + tr [user332325]:                        0.0021
[S   ] head + tr [eugene y]:                            0.0021
[S, P] dd + tr [mklement0]:                             0.0021
[M   ] printf + sed [user332325 (comment)]:             0.0021
[M   ] mawk - $(count+1)="=" [Steven Penny (variant)]:  0.0025
[M, P] mawk - while loop [Steven Penny]:                0.0026
[M   ] gawk - $(count+1)="=" [Steven Penny (variant)]:  0.0028
[M, P] gawk - while loop [Steven Penny]:                0.0028
[M   ] yes + head + tr [Digital Trauma]:                0.0029
[M   ] Perl [sid_com]:                                  0.0059
  • Bash 전용 솔루션이 팩을 이끌지 만 반복 횟수가 적습니다! (아래 참조).
  • 외부 유틸리티, 특히 Perl의 시작 비용이 중요합니다. 각 반복마다 반복 횟수 가 적은 루프에서 이것을 호출해야하는 경우 다중 유틸리티 awk, 및 perl솔루션을 피하십시오.

  • 반복 횟수 : 1000000 (1 백만)
[M   ] Perl [sid_com]:                                  0.0067
[M   ] mawk - $(count+1)="=" [Steven Penny (variant)]:  0.0254
[M   ] gawk - $(count+1)="=" [Steven Penny (variant)]:  0.0599
[S   ] head + tr [eugene y]:                            0.1143
[S, P] dd + tr [mklement0]:                             0.1144
[S   ] printf + tr [user332325]:                        0.1164
[M, P] mawk - while loop [Steven Penny]:                0.1434
[M   ] seq -f [Sam Salisbury]:                          0.1452
[M   ] jot -b [Stefan Ludwig]:                          0.1690
[M   ] printf + sed [user332325 (comment)]:             0.1735
[M   ] yes + head + tr [Digital Trauma]:                0.1883
[M, P] gawk - while loop [Steven Penny]:                0.2493
[M   ] awk - $(count+1)="=" [Steven Penny (variant)]:   0.2614
[M, P] awk - while loop [Steven Penny]:                 0.3211
[M, P] printf %.s= [dogbane]:                           2.4565
[M   ] echo -n - brace expansion loop [eugene y]:       7.5877
[M   ] echo -n - arithmetic loop [Eliah Kagan]:         13.5426
[M   ] printf + bash global substr. replacement [Tim]:  n/a
  • 질문의 펄 솔루션이 훨씬 빠릅니다.
  • Bash의 전역 문자열 교체 ( ${foo// /=})는 큰 문자열로 인해 예상치 못하게 느리게 진행되며 Bash 4.3.30에서 약 50 분 (!)이 걸리고 Bash 3.2.57에서 더 길어졌습니다. 완료).
  • 배쉬 루프는 느리고 산술 루프 ( (( i= 0; ... )))는 중괄호 확장 루프 ( )보다 느리지 {1..n}만 산술 루프는 메모리 효율성이 높습니다.
  • awk을 의미 BSD awk (뿐만 아니라 OSX에 있음) -이 눈에 띄게보다 느린이다 gawk(GNU awk는) 특히 mawk.
  • 많은 수와 다중 문자가 있음에 유의하십시오. 문자열을 사용하면 메모리 소비가 고려 될 수 있습니다. 이러한 점에서 접근 방식이 다릅니다.

위를 생성 한 Bash 스크립트 ( testrepeat)는 다음과 같습니다 . 두 가지 인수가 필요합니다.

  • 문자 반복 횟수
  • 선택적으로, 수행하고 평균 타이밍 을 계산하기위한 테스트 실행 횟수

즉 : 타이밍 위에 얻어졌다 testrepeat 100 1000testrepeat 1000000 1000

#!/usr/bin/env bash

title() { printf '%s:\t' "$1"; }

TIMEFORMAT=$'%6Rs'

# The number of repetitions of the input chars. to produce
COUNT_REPETITIONS=${1?Arguments: <charRepeatCount> [<testRunCount>]}

# The number of test runs to perform to derive the average timing from.
COUNT_RUNS=${2:-1}

# Discard the (stdout) output generated by default.
# If you want to check the results, replace '/dev/null' on the following
# line with a prefix path to which a running index starting with 1 will
# be appended for each test run; e.g., outFilePrefix='outfile', which
# will produce outfile1, outfile2, ...
outFilePrefix=/dev/null

{

  outFile=$outFilePrefix
  ndx=0

  title '[M, P] printf %.s= [dogbane]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  # !! In order to use brace expansion with a variable, we must use `eval`.
  eval "
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    printf '%.s=' {1..$COUNT_REPETITIONS} >"$outFile"
  done"

  title '[M   ] echo -n - arithmetic loop [Eliah Kagan]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    for ((i=0; i<COUNT_REPETITIONS; ++i)); do echo -n =; done >"$outFile"
  done


  title '[M   ] echo -n - brace expansion loop [eugene y]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  # !! In order to use brace expansion with a variable, we must use `eval`.
  eval "
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    for i in {1..$COUNT_REPETITIONS}; do echo -n =; done >"$outFile"
  done
  "

  title '[M   ] printf + sed [user332325 (comment)]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    printf "%${COUNT_REPETITIONS}s" | sed 's/ /=/g' >"$outFile"
  done


  title '[S   ] printf + tr [user332325]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    printf "%${COUNT_REPETITIONS}s" | tr ' ' '='  >"$outFile"
  done


  title '[S   ] head + tr [eugene y]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    head -c $COUNT_REPETITIONS < /dev/zero | tr '\0' '=' >"$outFile"
  done


  title '[M   ] seq -f [Sam Salisbury]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    seq -f '=' -s '' $COUNT_REPETITIONS >"$outFile"
  done


  title '[M   ] jot -b [Stefan Ludwig]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    jot -s '' -b '=' $COUNT_REPETITIONS >"$outFile"
  done


  title '[M   ] yes + head + tr [Digital Trauma]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    yes = | head -$COUNT_REPETITIONS | tr -d '\n'  >"$outFile"
  done

  title '[M   ] Perl [sid_com]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    perl -e "print \"=\" x $COUNT_REPETITIONS" >"$outFile"
  done

  title '[S, P] dd + tr [mklement0]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    dd if=/dev/zero bs=$COUNT_REPETITIONS count=1 2>/dev/null | tr '\0' "=" >"$outFile"
  done

  # !! On OSX, awk is BSD awk, and mawk and gawk were installed later.
  # !! On Linux systems, awk may refer to either mawk or gawk.
  for awkBin in awk mawk gawk; do
    if [[ -x $(command -v $awkBin) ]]; then

      title "[M   ] $awkBin"' - $(count+1)="=" [Steven Penny (variant)]'
      [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
      time for (( n = 0; n < COUNT_RUNS; n++ )); do 
        $awkBin -v count=$COUNT_REPETITIONS 'BEGIN { OFS="="; $(count+1)=""; print }' >"$outFile"
      done

      title "[M, P] $awkBin"' - while loop [Steven Penny]'
      [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
      time for (( n = 0; n < COUNT_RUNS; n++ )); do 
        $awkBin -v count=$COUNT_REPETITIONS 'BEGIN { while (i++ < count) printf "=" }' >"$outFile"
      done

    fi
  done

  title '[M   ] printf + bash global substr. replacement [Tim]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  # !! In Bash 4.3.30 a single run with repeat count of 1 million took almost
  # !! 50 *minutes*(!) to complete; n Bash 3.2.57 it's seemingly even slower -
  # !! didn't wait for it to finish.
  # !! Thus, this test is skipped for counts that are likely to be much slower
  # !! than the other tests.
  skip=0
  [[ $BASH_VERSINFO -le 3 && COUNT_REPETITIONS -gt 1000 ]] && skip=1
  [[ $BASH_VERSINFO -eq 4 && COUNT_REPETITIONS -gt 10000 ]] && skip=1
  if (( skip )); then
    echo 'n/a' >&2
  else
    time for (( n = 0; n < COUNT_RUNS; n++ )); do 
      { printf -v t "%${COUNT_REPETITIONS}s" '='; printf %s "${t// /=}"; } >"$outFile"
    done
  fi
} 2>&1 | 
 sort -t$'\t' -k2,2n | 
   awk -F $'\t' -v count=$COUNT_RUNS '{ 
    printf "%s\t", $1; 
    if ($2 ~ "^n/a") { print $2 } else { printf "%.4f\n", $2 / count }}' |
     column -s$'\t' -t

타이밍 비교를 보는 것은 흥미롭지 만 많은 프로그램에서 출력이 버퍼링되어 버퍼링이 꺼지면 타이밍이 변경 될 수 있다고 생각합니다.
Sergiy Kolodyazhnyy 2012 년

In order to use brace expansion with a variable, we must use `eval`👍
pyb

2
따라서 perl 솔루션 (sid_com)은 기본적으로 가장 빠릅니다 ... 일단 perl을 시작하는 초기 오버 헤드에 도달하면. (작은 반복의 경우 59ms에서 백만 반복의 경우 67ms로 진행됩니다. 따라서 펄 포킹은 시스템에서 약 59ms가 걸렸습니다)
Olivier Dulac

46

여러 가지 방법이 있습니다.

루프 사용하기 :

  • 중괄호 확장은 정수 리터럴과 함께 사용할 수 있습니다.

    for i in {1..100}; do echo -n =; done    
  • C와 같은 루프를 사용하면 변수를 사용할 수 있습니다.

    start=1
    end=100
    for ((i=$start; i<=$end; i++)); do echo -n =; done

printf내장 사용하기 :

printf '=%.0s' {1..100}

여기에 정밀도를 지정하면 지정된 너비 ( 0) 에 맞게 문자열이 잘립니다 . 으로 printf재사용 한 형식 문자열이 단순히 인쇄, 모든 인수를 소비하는 "="100 번.

사용 head( printf등)과 tr:

head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="

2
++는 반복 횟수가 많은 경우에도 잘 작동 하는 head/ tr솔루션입니다 (작은 경고 : head -cPOSIX 호환은 아니지만 BSD와 GNU 모두 head구현). 이 경우 다른 두 가지 솔루션은 느리지 만 다중 문자 문자열 로 작업하는 이점도 있습니다.
mklement0

1
사용 yes하고 head- 유용한 당신이 뉴 라인의 특정 번호를 원하는 경우 : yes "" | head -n 100. tr이 모든 문자를 인쇄 할 수 있습니다 :yes "" | head -n 100 | tr "\n" "="; echo
loxaxs

놀랍게도 : 버전 dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null보다 상당히 느립니다 head -c100000000 < /dev/zero | tr '\0' '=' >/dev/null. 물론 시차를 합리적으로 측정하려면 100M +의 블록 크기를 사용해야합니다. 100M 바이트는 표시된 두 개의 각 버전에서 1.7 초와 1 초가 걸립니다. 나는 tr을 벗어 버리고 방금 덤프 /dev/null하여 head버전 은 0.287 초, 버전은 0.675 초를 dd10 억 바이트로 얻었습니다 .
Michael Goldshteyn

예를 들어 : dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null=> 0,21332 s, 469 MB/s; 예를 들어 : dd if=/dev/zero count=100 bs=1000000| tr '\0' '=' >/dev/null=> 0,161579 s, 619 MB/s;
3ED

31

seq를 사용 하여이 작업을 수행하는 매우 쉬운 방법을 찾았습니다.

업데이트 : 이것은 seqOS X과 함께 제공 되는 BSD에서 작동합니다. 다른 버전의 YMMV

seq  -f "#" -s '' 10

다음과 같이 '#'을 10 번 인쇄합니다.

##########
  • -f "#"숫자를 무시하고 #각 숫자 에 대해 인쇄하도록 형식 문자열을 설정합니다 .
  • -s '' seq가 각 숫자 사이에 삽입하는 줄 바꿈을 제거하기 위해 구분 기호를 빈 문자열로 설정합니다.
  • 공간이 후 -f하고 -s중요한 것 같다.

편집 : 여기에 편리한 기능이 있습니다 ...

repeat () {
    seq  -f $1 -s '' $2; echo
}

이런 식으로 전화 할 수 있습니다 ...

repeat "#" 10

참고 : 반복 #하는 경우 따옴표가 중요합니다!


7
이것은 나에게 준다 seq: format ‘#’ has no % directive. seq문자열이 아니라 숫자입니다. 참조 gnu.org/software/coreutils/manual/html_node/seq-invocation.html
존 B

아, 그래서 OS X에있는 BSD 버전의 seq를 사용하고있었습니다. 나는 대답을 업데이트 할 것입니다. 어떤 버전을 사용하고 있습니까?
Sam Salisbury

GNU coreutils의 seq를 사용하고 있습니다.
John B

1
@JohnB : BSD seq문자열 을 복제하기 위해 여기에서 현명하게 용도가 변경 되었습니다 . 전달 된 형식 문자열 -일반적 으로 생성 되는 숫자의 형식을 지정하는 데 사용됨 -여기에 복제 할 문자열 만 포함되므로 출력에는 해당 문자열의 사본 만 포함됩니다. 불행히도 GNU 는 형식 문자열에 숫자 형식이 있다고 주장 합니다. 이는 오류입니다. -fseq
mklement0

1
잘 했어요; 다중 문자 문자열 과도 작동합니다 . 공백이 포함 된 문자열과 "$1"같은 문자를 전달할 수도 있으므로 (큰 따옴표)를 사용하십시오 '*'. 마지막으로을 사용 %하려면을 두 배로 늘려야 합니다 (그렇지 않으면 seq형식 지정의 일부라고 생각합니다 %f). 사용하는 "${1//%/%%}"것이 그것을 돌볼 것입니다. 당신이 사용하고 (당신이 언급으로) 때문에 BSD를 seq , 이것은 일반적으로 BSD와 같은 OS에서 작동합니다 (예를 들어, FreeBSD의) - 대조적으로, 그것은 리눅스에서 작동하지 않습니다 , GNU가 seq 사용된다.
mklement0

18

흥미로운 두 가지 방법이 있습니다.

우분투 @ 우분투 : ~ $ yes = | 머리 -10 | 붙여 넣기 -s -d ''-
==========
우분투 @ 우분투 : ~ $ yes = | 머리 -10 | tr -d "\ n"
========== ubuntu @ ubuntu : ~ $ 

이 둘은 미묘하게 다르다는 점에 유의하십시오.이 paste방법은 새로운 줄로 끝납니다. tr방법은하지 않습니다.


1
잘 했어요; 주의하시기 바랍니다 BSD는 paste 알수없는 요구 -d '\0'빈 구분 기호를 지정하기위한, 그리고 실패는 -d ''- -d '\0'모든 POSIX 호환 재치 작동합니다 paste구현 실제로 작동 GNU paste 도.
mklement0

선외 도구가 더 적은 정신과 비슷합니다.yes | mapfile -n 100 -C 'printf = \#' -c 1
감독

@bishop : 명령이 실제로 하나의 적은 수의 서브 쉘을 생성하지만 반복 횟수가 많을수록 여전히 느리며 반복 횟수가 적을수록 차이는 중요하지 않습니다. 정확한 임계 값은 하드웨어 및 OS에 따라 다를 수 있습니다. 예를 들어, OSX 10.11.5 시스템에서이 답변은 이미 500에서 더 빠릅니다. 시도하십시오 time yes = | head -500 | paste -s -d '\0' -; time yes | mapfile -n 500 -C 'printf = \#' -c 1. 그러나 더 중요한 것은, printf어쨌든 당신이 사용 하고 있다면 , 당신은 받아 들여진 대답으로부터 더 간단하고 더 효율적인 접근법을 이용할 수있을 것입니다.printf '%.s=' $(seq 500)
mklement0

13

간단한 방법은 없습니다. 루프를 사용 printf하고 대체 하지 마십시오 .

str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.

2
훌륭하지만 반복 횟수가 적 으면 합리적으로 수행됩니다. 여기에는 다음과 같이 호출 할 수있는 랩퍼 함수의 repl = 100예를 들어 (출력되지 않습니다 뒤에, \n:)repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
mklement0

1
@ mklement0 두 솔루션의 기능 버전을 모두 제공합니다. 둘 다 +1입니다!
Camilo Martin

8

다음과 같은 다른 구현 echoprintf및 / 또는 쉘에서 POSIX 준수 및 일관성을 원할 경우 bash:

seq(){ n=$1; while [ $n -le $2 ]; do echo $n; n=$((n+1)); done ;} # If you don't have it.

echo $(for each in $(seq 1 100); do printf "="; done)

... perl -E 'say "=" x 100'어디에서나 동일한 출력을 생성합니다 .


1
문제는 seqPOSIX 유틸리티가 아니라는 것 입니다 (BSD 및 Linux 시스템에는 구현이 있지만)- while@ Xennex81의 답변에서와 같이 대신 루프를 사용 하여 POSIX 셸 산술을 수행 할 수 있습니다 ( printf "=", 대신 올바르게 제안하십시오 echo -n).
mklement0

1
죄송합니다. 그 표준은 의미가 없기 때문에 그런 것들이 때로는 나를 지나쳐지나칩니다. calPOSIX입니다. seq아니다. 어쨌든 while 루프를 사용하여 답변을 다시 작성하는 대신 (이미 다른 답변에 있음) RYO 함수를 추가합니다. 그런 식으로 더 교육 ;-).
Geoff Nixon

8

문제는 그것을 사용하는 방법에 관한 것입니다 echo.

echo -e ''$_{1..100}'\b='

이 뜻은 정확히 동일한 작업을 수행합니다 perl -E 'say "=" x 100'있지만으로 echo만.


여분의 공백 백 스페이스를 만들지 않는 경우는 예외입니다. echo -e $ _ {1..100} '\ b ='| 열
앤서니

1
나쁜 생각. 경우에 실패합니다 $_1, $_2또는 백 개 변수에 다른 값을 가지고있다.
존 Kugelman

@JohnKugelman echo $ (set-; eval echo -e \ $ {{1..100}} '\\ b =')
mug896

이것은 심하다 . 나는 그것을 좋아한다 : D
dimo414

6

순수한 배쉬 방식 eval, 하위 셸, 외부 도구, 괄호 확장 (즉, 변수에서 숫자를 반복 할 수 있음) :

n음수가 아닌 숫자로 확장 되는 변수와 변수가 제공되는 경우 ( pattern예 :

$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello

이것으로 기능을 만들 수 있습니다 :

repeat() {
    # $1=number of patterns to repeat
    # $2=pattern
    # $3=output variable name
    local tmp
    printf -v tmp '%*s' "$1"
    printf -v "$3" '%s' "${tmp// /$2}"
}

이 세트로 :

$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello

이 작은 트릭을 위해 우리는 printf다음과 같이 많은 것을 사용합니다

  • -v varname: 표준 출력으로 인쇄하는 대신 printf형식화 된 문자열의 내용을 variable에 넣습니다 varname.
  • '% * s': printf인수를 사용하여 해당하는 수의 공백을 인쇄합니다. 예를 들어 printf '%*s' 4242 칸을 인쇄합니다.
  • 우리는 우리의 변수 공간의 원하는 수있을 때 마지막으로, 우리는 우리의 패턴에 의해 모든 공백을 대체 할 매개 변수 확장을 사용 ${var// /$pattern}의 확장에 확장됩니다 var모든 공간의 확장에 의해 대체와 함께 $pattern.

간접 확장을 사용하여 함수 에서 tmp변수를 제거 할 수도 있습니다 repeat.

repeat() {
    # $1=number of patterns to repeat
    # $2=pattern
    # $3=output variable name
    printf -v "$3" '%*s' "$1"
    printf -v "$3" '%s' "${!3// /$2}"
}

변수 이름을 전달하는 흥미로운 변형입니다.이 솔루션은 반복 횟수에 최대 1,000 개까지 가능하지만 (실제로 추측하면 대부분의 실제 응용 프로그램에는 적합 할 수 있음) 더 높은 수에 대해서는 매우 느립니다 (다음 참조). 논평).
mklement0

것으로 보인다 bash매개 변수 확장 (의 맥락에서의 글로벌 스트링 교체 작업이 ${var//old/new}극심한 느린 bash는 :) 특히 느린 3.2.57bash는 느린하고 4.3.30, 3.2 GHz의 인텔 코어 i5 시스템에서 내 OSX 10.10.3 시스템에서 적어도 :로를 1,000으로 카운트하면 속도가 느립니다 ( 3.2.57) / 빠름 ( 4.3.30) : 0.1 / 0.004 초 카운트를 10,000으로 늘리면 repeat 10000 = varbash에서 약 80 초 (!), bash 3.2.57에서 약 0.3 초가 걸립니다 4.3.30(on보다 훨씬 빠르지 3.2.57만 여전히 느립니다).
mklement0

6
#!/usr/bin/awk -f
BEGIN {
  OFS = "="
  NF = 100
  print
}

또는

#!/usr/bin/awk -f
BEGIN {
  while (z++ < 100) printf "="
}


3
잘 했어요; 이것은 POSIX를 준수하며 반복 횟수가 높더라도 상당히 빠르며 다중 문자 문자열도 지원합니다. 쉘 버전은 다음과 같습니다 awk 'BEGIN { while (c++ < 100) printf "=" }'.. 매개 변수화 된 쉘 함수로 래핑 됨 ( repeat 100 =예 : 로 호출 ) : repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }. (더러운 .접두사 char 및 보완 substr호출은 BSD의 버그를 해결하는 데 필요합니다 awk. 여기서 시작 하는 변수 값을 전달 =하면 명령 이 중단 됩니다 .)
mklement0

1
NF = 100솔루션 (100 얻을 불구하고 매우 영리하다 =, 당신이 사용해야합니다 NF = 101). 주의 사항이는 BSD 충돌한다는 것이다 awk(그러나 그것은 매우 빨리 gawk그리고 더 빨리와 mawk)과 POSIX에 나와있는이 둘 것을 할당하지NF,도 필드의 사용 BEGIN블록. awk약간의 수정만으로 BSD 에서도 작동하게 할 수 있습니다 awk 'BEGIN { OFS = "="; $101=""; print }'(그러나 흥미롭게도 awk루프 솔루션보다 빠르지 않은 BSD 에서는). 매개 변수화 된 쉘 솔루션으로 : repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }.
mklement0

사용자 참고 사항-NF = 100 트릭은 오래된 awk에서 세그먼트 오류를 ​​발생시킵니다. 이것은 original-awkBSD의 awk와 비슷한 이전 awk의 Linux에서 이름이며,이를 시도하면 충돌하는 것으로보고되었습니다. 충돌은 일반적으로 악용 가능한 버그를 찾기위한 첫 번째 단계입니다. 이 답변은 안전하지 않은 코드를 홍보합니다.

2
사용자에 대한 참고- original-awk비표준 적이며 권장되지 않음
Steven Penny

첫 번째 코드 조각에 대한 대안이 될 수 있습니다 awk NF=100 OFS='=' <<< ""(사용 bashgawk)
oliv

4

질문의 원래 목적은 쉘의 내장 명령 으로이 작업을 수행하는 것이 었습니다. 그래서 for루프와 printfs는, 합법적 인 것이지만 rep, perl, 또한 jot아래 않을 것입니다. 여전히 다음 명령

jot -s "/" -b "\\" $((COLUMNS/2))

예를 들어, 창 전체 줄을 인쇄합니다. \/\/\/\/\/\/\/\/\/\/\/\/


2
잘 했어요; 이 방법은 반복 횟수가 많은 경우에도 잘 작동합니다 (여러 문자 문자열도 지원함). 접근 방식을 더 잘 설명하기 위해 다음은 OP 명령과 동일 jot -s '' -b '=' 100합니다. 주의해야 할 점은 OSX를 포함한 BSD와 같은 플랫폼 jot에는 Linux 배포판이 포함되어 있지 않다는 것 입니다.
mklement0

1
고맙게도, 나는 당신의 -s 사용을 좋아합니다. 스크립트를 변경했습니다.
Stefan Ludwig

최근 데비안 기반 시스템에서는 apt install athena-jot을 제공합니다 jot.
agc

4

다른 사람들이 말했듯이, bash 괄호 확장은 매개 변수 확장 보다 우선 하므로 범위에는 리터럴 만 포함될 수 있습니다. 그리고 각에서 같은 쉘을 사용하는 경우에도 깨끗한 솔루션을 제공하지만, 한 시스템에서 다른 시스템으로 완벽하게 이식 할 수 없습니다. ( 예를 들어 FreeBSD 9.3 이상에서 점점 더 많이 이용 가능 하지만 ) 다른 형태의 간접적 인 지시는 항상 작동하지만 다소 우아하지는 않습니다.{m,n}seqjotseqeval

다행히도 bash 는 C 스타일 for 루프를 지원합니다 (산술 표현식 만 해당). 간결한 "순수한 배쉬"방법은 다음과 같습니다.

repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }

첫 번째 인수로 반복 횟수를, 두 번째 인수로 반복 할 문자열 (문제 설명에서와 같이 단일 문자 일 수 있음)을 사용합니다. repecho 7 b출력 bbbbbbb(개행으로 종료).

Dennis Williamson기본적으로이 솔루션을 4 년 전에 쉘 스크립트에서 반복되는 문자열 만들기 에 대한 탁월한 답변 을 제공했습니다 . 내 함수 본문은 코드와 약간 다릅니다.

  • 여기서 초점은 단일 문자를 반복하고 쉘은 bash이므로, echo대신 사용하는 것이 안전합니다 printf. 그리고이 질문의 문제 설명을 인쇄 기본 설정을 나타내는 것으로 읽었습니다 echo. 위 함수 정의는 bash 및 ksh93 에서 작동합니다 . 하지만 printf휴대 성이다 (일반적으로 이런 종류의에 사용한다) echo의 구문은 틀림없이 더 읽을 수 있습니다.

    일부 쉘의 echo내장 은 입력으로 stdin을 사용 -한다는 일반적인 의미가 . zsh 가이를 수행합니다. 그리고 확실히 존재 인식하지 못하는들 로, 이 표준되지 않습니다 . 많은 Bourne 스타일 쉘은 C 스타일 for 루프를 전혀 허용하지 않으므로 해당 동작을 고려할 필요가 없습니다.-echoecho-necho

  • 여기서 과제는 순서를 인쇄하는 것입니다. 거기 에 변수에 할당했습니다.

만약이 $n반복 원하는 수의 그리고 당신은 그것을 다시 사용할 필요가 없습니다, 당신은 심지어 짧은 뭔가를 원하는 :

while ((n--)); do echo -n "$s"; done; echo

n변수 여야합니다.이 방법은 위치 매개 변수에서 작동하지 않습니다. $s반복 할 텍스트입니다.


2
루프 버전을 사용하지 마십시오. printf "%100s" | tr ' ' '='최적입니다.
ocodo

기능을 기능으로 패키징하는 데 필요한 배경 정보 및 유용한 정보를 제공합니다 zsh. 반복 반향 방식은 반복 횟수가 적을수록 잘 작동하지만, 규모가 큰 반복의 경우 @Slomojo의 의견에서 알 수 있듯이 유틸리티 기반 POSIX 호환 대안이 있습니다.
mklement0

짧은 루프 주위에 괄호를 추가하면 에코에 영향을주지 않고 n 값이 유지됩니다.(while ((n--)); do echo -n "$s"; done; echo)

에코 대신 printf를 사용하십시오! 더 휴대하기 쉬운 방법입니다 (echo -n은 일부 시스템에서만 작동 할 수 있음). 참조 unix.stackexchange.com/questions/65803/... (스테판 Chazelas가의 멋진 대답 중 하나)
올리비에 Dulac

@OlivierDulac 여기서 질문은 배쉬에 관한 것입니다. 어떤 운영 체제를 실행하든 bash를 사용하는 경우 bash에는 echo을 지원 하는 내장 기능이 -n있습니다. 당신이 말하는 것의 정신은 절대적으로 정확합니다. 적어도 비대화 형 사용에서는 printf거의 항상가 선호됩니다 echo. 그러나 나는 echo질문을하고 그 질문이 효과가 있다는 것을 알기에 충분한 정보를 제공 한 질문에 대한 대답을하는 것이 부적절하거나 오해의 소지가 없다고 생각합니다 . POSIX는 ((n--))(없이 $) 지원을 보장하지 않습니다.
Eliah Kagan

4

파이썬은 어디에나 있으며 어디에서나 동일하게 작동합니다.

python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100

문자와 개수는 별도의 매개 변수로 전달됩니다.


나는 이것이 의도 였다고 생각한다python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
gazhay

@loevborg는 그렇게 많이 가져 오지 않았습니까?
Sapphire_Brick

3

bash 3.0 이상에서

for i in {1..100};do echo -n =;done

3

임의의 문자열을 n 번 반복하는 또 다른 방법 :

장점 :

  • POSIX 쉘과 함께 작동합니다.
  • 변수에 출력을 할당 할 수 있습니다.
  • 문자열을 반복합니다.
  • 반복이 매우 큰 경우에도 매우 빠릅니다.

단점 :

  • Gnu Core Utils의 yes명령이 필요합니다 .
#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"

ANSI 터미널과 US-ASCII 문자를 반복합니다. ANSI CSI 이스케이프 시퀀스를 사용할 수 있습니다. 문자를 반복하는 가장 빠른 방법입니다.

#!/usr/bin/env bash

char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"

또는 정적으로 :

줄을 80 번 인쇄하십시오 =.

printf '=\e[80b\n'

한계 :

  • 모든 터미널이 repeat_charANSI CSI 시퀀스를 이해하는 것은 아닙니다 .
  • US-ASCII 또는 1 바이트 ISO 문자 만 반복 할 수 있습니다.
  • 마지막 열에서 반복이 중지되므로 터미널 너비에 관계없이 큰 값을 사용하여 전체 행을 채울 수 있습니다.
  • 반복은 표시 전용입니다. 쉘 변수로 출력을 캡처하면 repeat_charANSI CSI 시퀀스가 ​​반복되는 문자로 확장되지 않습니다 .

1
사소한 참고-터미널이 줄 바꿈 모드 인 경우 REP (CSI b)가 정상적으로 줄 바꿈되어야합니다.
jerch

3

다음은 리눅스에서 화면 전체에 한 줄의 문자를 인쇄하는 데 사용하는 것입니다 (터미널 / 화면 너비 기준)

화면에서 "="를 인쇄하십시오.

printf '=%.0s' $(seq 1 $(tput cols))

설명:

주어진 순서만큼 등호를 인쇄하십시오.

printf '=%.0s' #sequence

명령의 출력을 사용하십시오 (명령 대체라는 bash 기능).

$(example_command)

예를 들어 1-20을 사용했습니다. 마지막 명령에서 tput 명령은 20 대신 사용됩니다.

seq 1 20

터미널에서 현재 사용되는 열 수를 지정하십시오.

tput cols


2
repeat() {
    # $1=number of patterns to repeat
    # $2=pattern
    printf -v "TEMP" '%*s' "$1"
    echo ${TEMP// /$2}
}

2

가장 간단한 방법은 csh / tcsh에서이 하나의 라이너를 사용하는 것입니다.

printf "%50s\n" '' | tr '[:blank:]' '[=]'


2

제안 된 Python 솔루션의보다 우아한 대안은 다음과 같습니다.

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

1

예를 들어 문자열의 길이에 따라 가변 횟수만큼 문자를 n 번 반복하려면 다음을 수행하십시오.

#!/bin/bash
vari='AB'
n=$(expr 10 - length $vari)
echo 'vari equals.............................: '$vari
echo 'Up to 10 positions I must fill with.....: '$n' equal signs'
echo $vari$(perl -E 'say "=" x '$n)

다음이 표시됩니다.

vari equals.............................: AB  
Up to 10 positions I must fill with.....: 8 equal signs  
AB========  

length작동하지 않습니다 expr, 당신은 아마 의미 n=$(expr 10 - ${#vari}); 그러나 Bash의 산술 확장을 사용하는 것이 더 간단하고 효율적 n=$(( 10 - ${#vari} ))입니다. 또한 귀하의 답변의 핵심은 OP가 Bash 대안 을 찾고있는 매우 Perl 접근법입니다 .
mklement0

1

이것은 Eliah Kagan이 말한 것의 더 긴 버전입니다.

while [ $(( i-- )) -gt 0 ]; do echo -n "  "; done

물론 printf를 사용할 수도 있지만 실제로는 좋아하지 않습니다.

printf "%$(( i*2 ))s"

이 버전은 대시와 호환됩니다 :

until [ $(( i=i-1 )) -lt 0 ]; do echo -n "  "; done

i는 초기 번호입니다.


bash에서 긍정적 인 n으로 while (( i-- )); do echo -n " "; done작동합니다.


1

에코로 어떻게 이것을 할 수 있습니까?

다음에 다음 과 같은 echo경우이 작업을 수행 할 수 있습니다 .echosed

echo | sed -r ':a s/^(.*)$/=\1/; /^={100}$/q; ba'

실제로 echo는 불필요합니다.


1

내 대답은 조금 더 복잡하고 완벽하지는 않지만 많은 수를 출력하려는 ​​사람들에게는 3 초 만에 약 천만을 할 수있었습니다.

repeatString(){
    # argument 1: The string to print
    # argument 2: The number of times to print
    stringToPrint=$1
    length=$2

    # Find the largest integer value of x in 2^x=(number of times to repeat) using logarithms
    power=`echo "l(${length})/l(2)" | bc -l`
    power=`echo "scale=0; ${power}/1" | bc`

    # Get the difference between the length and 2^x
    diff=`echo "${length} - 2^${power}" | bc`

    # Double the string length to the power of x
    for i in `seq "${power}"`; do 
        stringToPrint="${stringToPrint}${stringToPrint}"
    done

    #Since we know that the string is now at least bigger than half the total, grab however many more we need and add it to the string.
    stringToPrint="${stringToPrint}${stringToPrint:0:${diff}}"
    echo ${stringToPrint}
}

1

가장 간단한 방법은이 하나의 라이너를 bash에서 사용하는 것입니다.

seq 10 | xargs -n 1 | xargs -I {} echo -n  ===\>;echo


1

또 다른 옵션은 GNU seq를 사용하고 생성하는 모든 숫자와 줄 바꿈을 제거하는 것입니다.

seq -f'#%.0f' 100 | tr -d '\n0123456789'

이 명령은 #문자를 100 번 인쇄합니다 .


1

대부분의 기존 솔루션 모두에 달려 {1..10}있는 쉘의 구문 지원 bash과 - zsh- 특정과에 일을하지 않습니다 tcsh또는 오픈 BSD의 ksh대부분의 비 배쉬 sh.

다음은 OS X 및 모든 * BSD 시스템에서 작동합니다. 실제로, 다양한 유형의 장식 공간의 전체 매트릭스를 생성하는 데 사용할 수 있습니다.

$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$ 

슬프게도, 우리는 후행 줄 바꿈을 얻지 못합니다. printf '\n'접은 후에 여분으로 고정시킬 수 있습니다 .

$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$ 

참고 문헌 :


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.