Làm thế nào tôi có thể làm điều này với echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
hoặcpython -c 'print "=" * 100'
printf
với seq
)svrb=`printf '%.sv' $(seq $vrb)`
Làm thế nào tôi có thể làm điều này với echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
hoặcpython -c 'print "=" * 100'
printf
với seq
)svrb=`printf '%.sv' $(seq $vrb)`
Câu trả lời:
Bạn có thể dùng:
printf '=%.0s' {1..100}
Cách thức hoạt động:
Bash mở rộng {1..100} để lệnh trở thành:
printf '=%.0s' 1 2 3 4 ... 100
Tôi đã đặt định dạng của printf =%.0s
có nghĩa là nó sẽ luôn in một bản =
bất kể nó được đưa ra. Do đó, nó in 100 =
s.
repl = 100
Ví dụ, đây là một trình bao bọc chức năng mà bạn có thể gọi với ( eval
không may là cần có thủ thuật để căn cứ vào việc mở rộng dấu ngoặc trên một biến):repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
thay vì ví dụ $(seq 1 $limit)
.
$s%.0s
đến %.0s$s
dấu gạch ngang gây ra printf
lỗi.
printf
: nó tiếp tục áp dụng chuỗi định dạng cho đến khi không còn đối số. Tôi đã giả sử nó xử lý chuỗi định dạng chỉ một lần!
Không có cách nào dễ dàng. Nhưng ví dụ:
seq -s= 100|tr -d '[:digit:]'
Hoặc có thể là một cách tuân thủ tiêu chuẩn:
printf %100s |tr " " "="
Cũng có một tput rep
, nhưng đối với các thiết bị đầu cuối của tôi trong tay (xterm và linux) dường như họ không hỗ trợ nó :)
=
ký tự.
printf
tr
là giải pháp POSIX duy nhất bởi vì seq
, yes
và {1..3}
không phải là POSIX.
printf %100s | sed 's/ /abc/g'
- xuất ra 'abcabcabc ...'
tr
). Bạn cũng có thể mở rộng nó để một cái gì đó như printf "%${COLUMNS}s\n" | tr " " "="
.
wc
. Kết luận duy nhất tôi có thể rút ra từ đây là " seq
không nên sử dụng".
Mẹo đội mũ tới @ gniourf_gniourf cho đầu vào của anh ấy.
Lưu ý: Câu trả lời này không trả lời câu hỏi ban đầu, nhưng bổ sung cho các câu trả lời hiện có, hữu ích bằng cách so sánh hiệu suất .
Các giải pháp được so sánh chỉ về tốc độ thực hiện - các yêu cầu về bộ nhớ không được tính đến (chúng khác nhau giữa các giải pháp và có thể có vấn đề với số lần lặp lại lớn).
Tóm lược:
${var// /=}
:), vì nó rất chậm.Sau đây là các định thời được thực hiện trên iMac cuối năm 2012 với CPU Intel Core i5 3,2 GHz và Fusion Drive, chạy OSX 10.10.4 và bash 3.2.57 và trung bình 1000 lần chạy.
Các mục là:
M
... một giải pháp đa vi khuẩn tiềm năngS
... một đơn giải pháp của ký tự chỉP
... một giải pháp tuân thủ POSIX[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
awk
và perl
các giải pháp.[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
${foo// /=}
) không thể giải thích được một cách khó hiểu với các chuỗi lớn và đã được đưa ra khỏi hoạt động (mất khoảng 50 phút (!) Trong Bash 4.3.30, và thậm chí lâu hơn nữa trong Bash 3.2.57 - Tôi không bao giờ chờ đợi nó kết thúc)(( i= 0; ... ))
) chậm hơn các vòng lặp mở rộng ( {1..n}
) - mặc dù các vòng lặp số học có hiệu quả bộ nhớ cao hơn.awk
đề cập đến BSD awk
(cũng được tìm thấy trên OSX) - nó chậm hơn đáng kể so với gawk
(GNU Awk) và đặc biệt mawk
.Đây là tập lệnh Bash ( testrepeat
) đã tạo ra ở trên. Phải mất 2 đối số:
Nói cách khác: thời gian trên đã thu được với testrepeat 100 1000
vàtestrepeat 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
In order to use brace expansion with a variable, we must use `eval`
👍
Có nhiều hơn một cách để làm điều đó.
Sử dụng một vòng lặp:
Mở rộng cú đúp có thể được sử dụng với chữ nguyên:
for i in {1..100}; do echo -n =; done
Một vòng lặp giống như C cho phép sử dụng các biến:
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; done
Sử dụng printf
nội dung:
printf '=%.0s' {1..100}
Chỉ định độ chính xác ở đây cắt ngắn chuỗi để phù hợp với chiều rộng đã chỉ định ( 0
). Khi printf
sử dụng lại chuỗi định dạng để sử dụng tất cả các đối số, điều này chỉ cần in "="
100 lần.
Sử dụng head
( printf
, v.v.) và tr
:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
head
/ tr
, hoạt động tốt ngay cả với số lần lặp lại cao (cảnh báo nhỏ: head -c
không tuân thủ POSIX, nhưng cả BSD và GNU đều head
thực hiện nó); trong khi hai giải pháp còn lại sẽ chậm trong trường hợp đó, chúng cũng có lợi thế là làm việc với các chuỗi đa chuỗi.
yes
và head
- hữu ích nếu bạn muốn có một số dòng mới nhất định : yes "" | head -n 100
. tr
có thể làm cho nó in bất kỳ ký tự nào:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
chậm hơn đáng kể so với head -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
phiên bản. Tất nhiên bạn phải sử dụng kích thước khối 100M + để đo chênh lệch thời gian một cách hợp lý. 100M byte mất 1,7 giây và 1 giây với hai phiên bản tương ứng được hiển thị. Tôi đã gỡ bỏ tr và chỉ đổ nó vào /dev/null
và nhận 0,287 giây cho head
phiên bản và 0,675 giây cho dd
phiên bản cho một tỷ byte.
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
=> 0,21332 s, 469 MB/s
; Vì: dd if=/dev/zero count=100 bs=1000000| tr '\0' '=' >/dev/null
=> 0,161579 s, 619 MB/s
;
Tôi vừa tìm thấy một cách dễ dàng nghiêm túc để làm điều này bằng cách sử dụng seq:
CẬP NHẬT: Điều này hoạt động trên BSD seq
đi kèm với OS X. YMMV với các phiên bản khác
seq -f "#" -s '' 10
Sẽ in '#' 10 lần, như thế này:
##########
-f "#"
đặt chuỗi định dạng để bỏ qua các số và chỉ in #
cho mỗi số.-s ''
đặt dấu phân cách thành một chuỗi trống để loại bỏ các dòng mới mà seq chèn giữa mỗi số-f
và -s
dường như là quan trọng.EDIT: Đây là một chức năng tiện dụng ...
repeat () {
seq -f $1 -s '' $2; echo
}
Mà bạn có thể gọi như thế này ...
repeat "#" 10
LƯU Ý: Nếu bạn đang lặp lại #
thì các trích dẫn rất quan trọng!
seq: format ‘#’ has no % directive
. seq
là cho số, không phải là chuỗi. Xem gnu.org/software/coreutils/manual/html_node/seq-invocation.html
seq
đã được khéo léo thêm thắt vào đây để lặp lại chuỗi : chuỗi định dạng truyền cho -f
- thường được sử dụng để định dạng số được tạo ra - chỉ chứa các chuỗi lặp lại ở đây để đầu ra chứa các bản sao của chỉ chuỗi đó. Thật không may, GNU seq
nhấn mạnh vào sự hiện diện của một định dạng số trong chuỗi định dạng, đó là lỗi bạn đang thấy.
"$1"
(dấu ngoặc kép), vì vậy bạn cũng có thể chuyển qua các ký tự như '*'
và chuỗi có khoảng trắng được nhúng. Cuối cùng, nếu bạn muốn có thể sử dụng %
, bạn phải nhân đôi nó (nếu không seq
sẽ nghĩ đó là một phần của đặc tả định dạng, chẳng hạn như %f
); sử dụng "${1//%/%%}"
sẽ chăm sóc điều đó. Vì (như bạn đã đề cập) bạn đang sử dụng BSD seq
, nên nó sẽ hoạt động trên các HĐH giống như BSD nói chung (ví dụ, FreeBSD) - ngược lại, nó sẽ không hoạt động trên Linux , nơi GNU seq
được sử dụng.
Đây là hai cách thú vị:
ubfox @ ubfox: ~ $ yes = | đầu -10 | dán -s -d '' - ========== ubfox @ ubfox: ~ $ yes = | đầu -10 | tr -d "\ n" ========== ubfox @ ubfox: ~ $
Lưu ý hai cái này khác nhau một cách tinh tế - paste
Phương thức kết thúc trong một dòng mới. Các tr
phương pháp không.
paste
không thể giải thích được yêu cầu -d '\0'
xác định một dấu phân cách trống và thất bại với -d ''
- -d '\0'
nên hoạt động với tất cả các paste
triển khai tương thích POSIX và thực sự cũng hoạt động với GNU paste
.
yes | mapfile -n 100 -C 'printf = \#' -c 1
time yes = | head -500 | paste -s -d '\0' -; time yes | mapfile -n 500 -C 'printf = \#' -c 1
. Tuy nhiên, quan trọng hơn: nếu bạn vẫn đang sử dụng printf
, bạn cũng có thể sử dụng cách tiếp cận đơn giản và hiệu quả hơn từ câu trả lời được chấp nhận:printf '%.s=' $(seq 500)
Không có cách nào đơn giản. Tránh các vòng lặp sử dụng printf
và thay thế.
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
repl = 100
Ví dụ, đây là một trình bao bọc hàm có thể được gọi như (không tạo ra dấu vết \n
):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
Nếu bạn muốn tuân thủ POSIX và tính nhất quán trong các triển khai khác nhau echo
và printf
, và / hoặc các vỏ khác ngoài 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)
... sẽ tạo ra cùng một đầu ra như perl -E 'say "=" x 100'
mọi nơi.
seq
không phải là tiện ích POSIX (mặc dù các hệ thống BSD và Linux có triển khai nó) - while
thay vào đó, bạn có thể thực hiện số học vỏ POSIX với một vòng lặp, như trong câu trả lời của @ Xennex81 (thay vì printf "="
, như bạn đề xuất chính xác, thay vì echo -n
).
cal
là POSIX. seq
không phải. Dù sao, thay vì viết lại câu trả lời bằng một vòng lặp while (như bạn nói, điều đó đã có trong các câu trả lời khác) Tôi sẽ thêm một hàm RYO. Giáo dục nhiều hơn theo cách đó ;-).
Câu hỏi là về cách thực hiện với echo
:
echo -e ''$_{1..100}'\b='
Điều này sẽ làm chính xác như perl -E 'say "=" x 100'
nhưng echo
chỉ với .
$_1
, $_2
hoặc bất kỳ biến nào khác trong số hàng trăm biến có giá trị.
Một cách Bash thuần túy không có eval
, không có subshells, không có công cụ bên ngoài, không mở rộng dấu ngoặc (nghĩa là bạn có thể có số để lặp lại trong một biến):
Nếu bạn được cung cấp một biến n
mở rộng thành số (không âm) và một biến pattern
, ví dụ:
$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello
Bạn có thể thực hiện một chức năng với điều này:
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}"
}
Với bộ này:
$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello
Đối với mẹo nhỏ này, chúng tôi sử dụng printf
khá nhiều với:
-v varname
: thay vì in ra đầu ra tiêu chuẩn, printf
sẽ đặt nội dung của chuỗi được định dạng vào biến varname
.printf
sẽ sử dụng đối số để in số lượng khoảng trắng tương ứng. Ví dụ, printf '%*s' 42
sẽ in 42 khoảng trắng.${var// /$pattern}
sẽ mở rộng sang mở rộng var
với tất cả các khoảng trắng được thay thế bằng việc mở rộng $pattern
.Bạn cũng có thể loại bỏ tmp
biến trong repeat
hàm bằng cách sử dụng mở rộng gián tiếp:
repeat() {
# $1=number of patterns to repeat
# $2=pattern
# $3=output variable name
printf -v "$3" '%*s' "$1"
printf -v "$3" '%s' "${!3// /$2}"
}
bash
các hoạt động thay thế chuỗi toàn cầu trong bối cảnh mở rộng tham số ( ${var//old/new}
) đặc biệt chậm: bash cực kỳ chậm và bash 3.2.57
chậm 4.3.30
, ít nhất là trên hệ thống OSX 10.10.3 của tôi trên máy Intel Core i5 3.2 Ghz: Với số lượng 1.000, mọi thứ chậm ( 3.2.57
) / nhanh ( 4.3.30
): 0,1 / 0,004 giây. Việc tăng số lượng lên 10.000 mang lại những con số khác nhau đáng kinh ngạc: repeat 10000 = var
mất khoảng 80 giây (!) Trong bash 3.2.57
và khoảng 0,3 giây trong bash 4.3.30
(nhanh hơn nhiều so với bật 3.2.57
, nhưng vẫn chậm).
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
Hoặc là
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
awk 'BEGIN { while (c++ < 100) printf "=" }'
. Được gói vào một hàm shell được tham số hóa ( repeat 100 =
ví dụ như gọi ) : repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }
. (Cần có .
tiền tố giả char và substr
cuộc gọi bổ sung để khắc phục lỗi trong BSD awk
, trong đó việc chuyển một giá trị biến bắt đầu bằng =
ngắt lệnh.)
NF = 100
giải pháp là rất thông minh (mặc dù để có được 100 =
, bạn phải sử dụng NF = 101
). Hãy cẩn thận là nó bị treo BSD awk
(nhưng nó rất nhanh với gawk
và thậm chí nhanh hơn với mawk
), và rằng POSIX thảo luận không phải gán cho NF
, và cũng không sử dụng các trường trong BEGIN
khối. Bạn cũng có thể làm cho nó hoạt động trong BSD awk
với một điều chỉnh nhỏ: awk 'BEGIN { OFS = "="; $101=""; print }'
(nhưng thật kỳ lạ, trong BSD awk
không nhanh hơn giải pháp vòng lặp). Là một giải pháp vỏ tham số : repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }
.
original-awk
là tên dưới Linux của awk cũ tương tự như awk BSD, mà cũng đã được báo cáo sụp đổ, nếu bạn muốn thử điều này. Lưu ý rằng sự cố thường là bước đầu tiên để tìm ra lỗi có thể khai thác. Câu trả lời này là để thúc đẩy mã không an toàn.
original-awk
không chuẩn và không được đề xuất
awk NF=100 OFS='=' <<< ""
(sử dụng bash
và gawk
)
Tôi đoán mục đích ban đầu của câu hỏi là làm điều này chỉ với các lệnh tích hợp của shell. Vì vậy, for
các vòng lặp và printf
s sẽ là hợp pháp, trong khi rep
, perl
và cũngjot
dưới đây sẽ không được. Tuy nhiên, lệnh sau
jot -s "/" -b "\\" $((COLUMNS/2))
ví dụ, in một dòng trên toàn cửa sổ \/\/\/\/\/\/\/\/\/\/\/\/
jot -s '' -b '=' 100
. Thông báo trước là trong khi các nền tảng giống như BSD, bao gồm OSX, đi kèm jot
, các bản phân phối Linux thì không .
apt install athena-jot
sẽ cung cấp jot
.
Như những người khác đã nói, trong bash brace mở rộng trước mở rộng tham số , vì vậy phạm vi chỉ có thể chứa chữ. và cung cấp các giải pháp sạch nhưng không hoàn toàn di động từ hệ thống này sang hệ thống khác, ngay cả khi bạn đang sử dụng cùng một vỏ trên mỗi hệ thống. (Mặc dù ngày càng có sẵn; ví dụ: trong FreeBSD 9.3 trở lên .){m,n}
seq
jot
seq
eval
Và các hình thức gián tiếp khác luôn hoạt động nhưng có phần không phù hợp.
May mắn thay, bash hỗ trợ kiểu C cho các vòng lặp (chỉ với các biểu thức số học). Vì vậy, đây là một cách "bash tinh khiết" súc tích:
repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
Điều này lấy số lần lặp lại làm đối số đầu tiên và chuỗi được lặp lại (có thể là một ký tự đơn lẻ, như trong mô tả vấn đề) làm đối số thứ hai. repecho 7 b
đầu ra bbbbbbb
(kết thúc bởi một dòng mới).
Dennis Williamson về cơ bản đã đưa ra giải pháp này bốn năm trước trong câu trả lời xuất sắc của ông về Tạo chuỗi các ký tự lặp lại trong kịch bản shell . Cơ thể chức năng của tôi hơi khác với mã ở đó:
Vì trọng tâm ở đây là lặp lại một ký tự và vỏ là bash, nên có thể sử dụng echo
thay vì an toàn printf
. Và tôi đọc mô tả vấn đề trong câu hỏi này như thể hiện một sở thích để in echo
. Định nghĩa hàm trên hoạt động trong bash và ksh93 . Mặc dù printf
dễ mang theo hơn (và thường được sử dụng cho loại điều này), echo
cú pháp của nó có thể dễ đọc hơn.
Bản thân một số shell của nó echo
diễn giải -
như là một tùy chọn - mặc dù ý nghĩa thông thường của -
việc sử dụng stdin cho đầu vào là vô nghĩa đối với echo
. zsh làm điều này. Và chắc chắn có tồn tại echo
mà không nhận ra -n
, vì nó không phải là tiêu chuẩn . (Nhiều shell kiểu Bourne hoàn toàn không chấp nhận kiểu C cho các vòng lặp, do đó echo
hành vi của chúng không cần phải xem xét ..)
Ở đây, nhiệm vụ là in trình tự; ở đó , nó được gán cho một biến.
Nếu $n
là số lần lặp lại mong muốn và bạn không phải sử dụng lại nó và bạn muốn một cái gì đó thậm chí ngắn hơn:
while ((n--)); do echo -n "$s"; done; echo
n
phải là một biến - cách này không hoạt động với các tham số vị trí. $s
là văn bản được lặp lại.
printf "%100s" | tr ' ' '='
là tối ưu.
zsh
tình cờ. Cách tiếp cận vòng lặp echo hoạt động tốt đối với số lần lặp lại nhỏ hơn, nhưng đối với các phương pháp lớn hơn có các lựa chọn thay thế tuân thủ POSIX dựa trên các tiện ích , bằng chứng là nhận xét của @ Slomojo.
(while ((n--)); do echo -n "$s"; done; echo)
echo
hỗ trợ -n
. Tinh thần của những gì bạn đang nói là hoàn toàn chính xác. printf
hầu như luôn luôn được ưu tiên echo
, ít nhất là trong sử dụng không tương tác. Nhưng tôi không nghĩ rằng bằng mọi cách không phù hợp hoặc gây hiểu lầm để đưa ra echo
câu trả lời cho một câu hỏi yêu cầu và cung cấp đủ thông tin để biết rằng nó sẽ hoạt động . Cũng xin lưu ý rằng hỗ trợ cho ((n--))
(không có a $
) tự nó không được đảm bảo bởi POSIX.
Python có mặt khắp nơi và hoạt động giống nhau ở mọi nơi.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
Ký tự và số lượng được truyền dưới dạng tham số riêng biệt.
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
Một nghĩa khác để lặp lại một chuỗi tùy ý n lần:
Ưu điểm:
Nhược điểm:
yes
lệnh của Gnu Core Utils .#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
Với một thiết bị đầu cuối ANSI và các ký tự US-ASCII để lặp lại. Bạn có thể sử dụng chuỗi thoát ANSI CSI. Đó là cách nhanh nhất để lặp lại một nhân vật.
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
Hoặc tĩnh:
In một dòng 80 lần =
:
printf '=\e[80b\n'
Hạn chế:
repeat_char
trình tự ANSI CSI.repeat_char
ANSI CSI thành ký tự lặp lại.Đây là những gì tôi sử dụng để in một dòng ký tự trên màn hình trong linux (dựa trên độ rộng của thiết bị đầu cuối / màn hình)
printf '=%.0s' $(seq 1 $(tput cols))
Giải trình:
In một dấu bằng nhiều lần như trình tự đã cho:
printf '=%.0s' #sequence
Sử dụng đầu ra của một lệnh (đây là một tính năng bash được gọi là Thay thế lệnh):
$(example_command)
Đưa ra một chuỗi, tôi đã sử dụng 1 đến 20 làm ví dụ. Trong lệnh cuối cùng, lệnh tput được sử dụng thay vì 20:
seq 1 20
Cho số lượng cột hiện đang được sử dụng trong thiết bị đầu cuối:
tput cols
for i in {1..100}
do
echo -n '='
done
echo
Đơn giản nhất là sử dụng một lớp lót này trong csh / tcsh:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
Một giải pháp thay thế thanh lịch hơn cho giải pháp Python được đề xuất có thể là:
python -c 'print "="*(1000)'
Trong trường hợp bạn muốn lặp lại một ký tự n lần là số lần VARIABLE tùy thuộc vào độ dài của chuỗi bạn có thể làm:
#!/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)
Nó sẽ hiển thị:
vari equals.............................: AB
Up to 10 positions I must fill with.....: 8 equal signs
AB========
length
sẽ không làm việc với expr
, bạn có thể có nghĩa là n=$(expr 10 - ${#vari})
; tuy nhiên, sử dụng mở rộng số học của Bash đơn giản và hiệu quả hơn : n=$(( 10 - ${#vari} ))
. Ngoài ra, cốt lõi của câu trả lời của bạn là cách tiếp cận Perl mà OP đang tìm kiếm một giải pháp thay thế Bash .
Đây là phiên bản dài hơn của những gì Eliah Kagan đã tham gia:
while [ $(( i-- )) -gt 0 ]; do echo -n " "; done
Tất nhiên bạn cũng có thể sử dụng printf cho điều đó, nhưng không thực sự theo ý thích của tôi:
printf "%$(( i*2 ))s"
Phiên bản này tương thích với Dash:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
với tôi là số ban đầu.
function repeatString()
{
local -r string="${1}"
local -r numberToRepeat="${2}"
if [[ "${string}" != '' && "${numberToRepeat}" =~ ^[1-9][0-9]*$ ]]
then
local -r result="$(printf "%${numberToRepeat}s")"
echo -e "${result// /${string}}"
fi
}
Chạy mẫu
$ repeatString 'a1' 10
a1a1a1a1a1a1a1a1a1a1
$ repeatString 'a1' 0
$ repeatString '' 10
Tham khảo lib tại: https://github.com/gdbtek/linux-cookbooks/blob/master/lologists/util.bash
Câu trả lời của tôi phức tạp hơn một chút và có lẽ không hoàn hảo, nhưng đối với những người muốn sản xuất số lượng lớn, tôi đã có thể làm được khoảng 10 triệu trong 3 giây.
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}
}
Hầu hết các giải pháp hiện có đều phụ thuộc vào {1..10}
hỗ trợ cú pháp của trình bao, cụ thể - bash
và zsh
- cụ thể và không hoạt động trong tcsh
hoặc OpenBSD ksh
và hầu hết không bash sh
.
Các thao tác sau sẽ hoạt động trên OS X và tất cả các hệ thống * BSD trong bất kỳ hệ vỏ nào; trong thực tế, nó có thể được sử dụng để tạo ra một ma trận gồm nhiều loại không gian trang trí khác nhau:
$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$
Đáng buồn thay, chúng tôi không nhận được một dòng mới; có thể được sửa bởi một phụ printf '\n'
sau khi gấp:
$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$
Người giới thiệu:
Đề xuất của tôi (chấp nhận giá trị biến cho n):
n=100
seq 1 $n | xargs -I {} printf =