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

어떻게하면 echo됩니까?

perl -E 'say "=" x 100'



답변

당신이 사용할 수있는:

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

작동 원리 :

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

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

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


답변

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

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

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

printf %100s |tr " " "="

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


답변

그의 입력 을 위해 @ 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


답변

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

루프 사용하기 :

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

    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 " " "="


답변

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

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

seq  -f "#" -s '' 10

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

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

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

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

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

repeat "#" 10

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


답변

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

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

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


답변

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

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