ฉันจะทำสิ่งนี้ด้วยได้echo
อย่างไร
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
หรือpython -c 'print "=" * 100'
printf
กับseq
)svrb=`printf '%.sv' $(seq $vrb)`
ฉันจะทำสิ่งนี้ด้วยได้echo
อย่างไร
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
หรือpython -c 'print "=" * 100'
printf
กับseq
)svrb=`printf '%.sv' $(seq $vrb)`
คำตอบ:
คุณสามารถใช้ได้:
printf '=%.0s' {1..100}
มันทำงานอย่างไร:
Bash ขยาย {1..100} ดังนั้นคำสั่งจะกลายเป็น:
printf '=%.0s' 1 2 3 4 ... 100
ฉันได้ตั้งค่ารูปแบบของ printf =%.0s
ซึ่งหมายความว่ามันจะพิมพ์เพียงครั้งเดียว=
ไม่ว่าจะมีการโต้แย้งอะไรก็ตาม ดังนั้นจึงพิมพ์ 100 =
วินาที
repl = 100
( eval
จำเป็นต้องใช้repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
$(seq 1 $limit)
$s%.0s
เป็น%.0s$s
มิฉะนั้นจะทำให้เกิดprintf
ข้อผิดพลาด
printf
: มันจะยังคงใช้สตริงรูปแบบจนกว่าจะไม่มีข้อโต้แย้งเหลืออยู่ ฉันคิดว่ามันประมวลผลสตริงรูปแบบเพียงครั้งเดียว!
ไม่มีวิธีง่ายๆ แต่ตัวอย่างเช่น:
seq -s= 100|tr -d '[:digit:]'
หรืออาจเป็นวิธีที่ได้มาตรฐาน:
printf %100s |tr " " "="
นอกจากนี้ยังมีtput rep
แต่สำหรับมือถือของฉัน (xterm และ linux) พวกเขาดูเหมือนจะไม่สนับสนุน :)
=
อักขระ
printf
tr
เป็นเพียงการแก้ปัญหา POSIX เพราะseq
, yes
และ{1..3}
ไม่ได้ POSIX
printf %100s | sed 's/ /abc/g'
- เอาต์พุต 'abcabcabc ... '
tr
) printf "%${COLUMNS}s\n" | tr " " "="
นอกจากนี้คุณยังสามารถขยายไปยังสิ่งที่ต้องการ
wc
ที่ผ่านมาโดยไม่ได้ตั้งใจด้วย ข้อสรุปเดียวที่ฉันทำได้จากนี้คือ " seq
ไม่ควรใช้"
เคล็ดลับของหมวกถึง @ gniourf_gniourfสำหรับการป้อนข้อมูลของเขา
หมายเหตุ: คำตอบนี้ไม่ได้ตอบคำถามเดิม แต่เติมเต็มคำตอบที่มีอยู่และเป็นประโยชน์โดยการเปรียบเทียบประสิทธิภาพเปรียบเทียบประสิทธิภาพการทำงาน
โซลูชั่นจะถูกเปรียบเทียบในแง่ของความเร็วในการดำเนินการเท่านั้น - ข้อกำหนดหน่วยความจำไม่ได้เป็นถูกนำมาพิจารณา
สรุป:
${var// /=}
) เนื่องจากมีข้อห้ามที่ช้าต่อไปนี้คือเวลาใน iMac ช่วงปลายปี 2012 ด้วยซีพียู Intel Core i5 3.2 GHz และฟิวชั่นไดรฟ์ใช้ OSX 10.10.4 และทุบตี 3.2.57 และเฉลี่ย 1,000 ครั้ง
รายการคือ:
M
... วิธีแก้ปัญหาที่มีหลายตัวเลือกS
... ทางออกเดียว -character เท่านั้นP
... โซลูชันที่สอดคล้องกับ 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
และperl
การแก้ปัญหา[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// /=}
) นั้นช้ามากอย่างน่าอัศจรรย์กับสตริงจำนวนมากและถูกนำออกจากการแข่งขัน (ใช้เวลาประมาณ 50 นาที (!) ใน Bash 4.3.30 และนานกว่าใน Bash 3.2.57 - ฉันไม่เคยรอ เสร็จสิ้น)(( i= 0; ... ))
) จะช้ากว่า brace-extended ( {1..n}
) - ถึงแม้ว่า arithmetic loops จะมีประสิทธิภาพในการใช้หน่วยความจำมากกว่าawk
อ้างถึงBSD awk
(เท่าที่พบใน OSX) - มันช้ากว่าอย่างเห็นได้ชัดgawk
(GNU Awk) และโดยเฉพาะอย่างยิ่งmawk
และโดยเฉพาะอย่างยิ่งนี่คือสคริปต์ Bash ( testrepeat
) ที่สร้างรายการด้านบน ใช้เวลา 2 ข้อโต้แย้ง:
กล่าวอีกนัยหนึ่ง: การกำหนดเวลาด้านบนได้ด้วยtestrepeat 100 1000
และ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`
👍
มีมากกว่าหนึ่งวิธีที่จะทำ
ใช้วง:
การขยายรั้งสามารถใช้กับตัวอักษรจำนวนเต็ม:
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
builtin:
printf '=%.0s' {1..100}
การระบุความแม่นยำที่นี่ตัดสตริงให้พอดีกับความกว้างที่ระบุ ( 0
) เมื่อprintf
นำสตริงการจัดรูปแบบกลับมาใช้เพื่อใช้อาร์กิวเมนต์ทั้งหมดพิมพ์เพียง"="
100 ครั้ง
ใช้head
( printf
, ฯลฯ ) และtr
:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
head
/ tr
โซลูชันซึ่งทำงานได้ดีแม้จะมีจำนวนการทำซ้ำสูง (คำเตือนเล็ก ๆ : head -c
ไม่สอดคล้องกับ POSIX แต่ทั้ง BSD และ GNU head
ใช้งานได้); ในขณะที่อีกสองโซลูชั่นจะช้าในกรณีนั้นพวกเขามีข้อได้เปรียบในการทำงานกับสตริงหลายตัวเช่นกัน
yes
และhead
- yes "" | head -n 100
มีประโยชน์ถ้าคุณต้องการจำนวนหนึ่งของการขึ้นบรรทัดใหม่: tr
สามารถทำให้มันพิมพ์ตัวอักษรใด ๆ :yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
ช้ากว่าhead -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
รุ่นมาก แน่นอนคุณต้องใช้ขนาดบล็อก 100M + เพื่อวัดความแตกต่างของเวลาอย่างสมเหตุสมผล 100M bytes ใช้เวลา 1.7 วินาทีและ 1 วินาทีพร้อมทั้งสองรุ่นตามลำดับที่แสดง ฉันถอด tr และเพิ่งทิ้งไป/dev/null
และรับ 0.287 s สำหรับhead
รุ่นและ 0.675 s สำหรับdd
รุ่นเป็นพันล้านไบต์
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
;
ฉันเพิ่งพบวิธีที่ง่ายอย่างจริงจังในการทำเช่นนี้โดยใช้ seq:
อัปเดต: ใช้งานได้กับ BSD seq
ที่มาพร้อมกับ OS X. YMMV กับเวอร์ชันอื่น
seq -f "#" -s '' 10
จะพิมพ์ '#' 10 ครั้งเช่นนี้
##########
-f "#"
กำหนดสตริงรูปแบบเพื่อละเว้นตัวเลขและเพียงพิมพ์#
สำหรับแต่ละคน-s ''
ตั้งค่าตัวคั่นเป็นสตริงว่างเพื่อลบบรรทัดใหม่ที่ seq แทรกระหว่างแต่ละหมายเลข-f
และ-s
ดูเหมือนจะมีความสำคัญแก้ไข: ที่นี่มันอยู่ในฟังก์ชั่นที่มีประโยชน์ ...
repeat () {
seq -f $1 -s '' $2; echo
}
ซึ่งคุณสามารถโทรแบบนี้ ...
repeat "#" 10
หมายเหตุ:หากคุณกำลังทำซ้ำ#
คำพูดนั้นมีความสำคัญ!
seq: format ‘#’ has no % directive
นี้จะช่วยให้ฉัน seq
ใช้สำหรับตัวเลขไม่ใช่สตริง ดูgnu.org/software/coreutils/manual/html_node/seq-invocation.html
seq
กำลังrepurposedที่นี่อย่างชาญฉลาดเพื่อทำซ้ำสตริง : สตริงรูปแบบที่ส่งผ่าน-f
- ปกติใช้เพื่อจัดรูปแบบตัวเลขที่สร้างขึ้น - มีเฉพาะสตริงที่จะทำซ้ำที่นี่เพื่อให้ผลลัพธ์มีสำเนาของสตริงนั้นเท่านั้น น่าเสียดายที่ GNU seq
ยืนยันว่ามีรูปแบบตัวเลขในสตริงรูปแบบซึ่งเป็นข้อผิดพลาดที่คุณเห็น
"$1"
(เครื่องหมายคำพูดคู่) เพื่อให้คุณสามารถส่งผ่านตัวอักษรเช่น'*'
และสตริงที่มีช่องว่างในตัว สุดท้ายหากคุณต้องการใช้งาน%
คุณต้องเพิ่มเป็นสองเท่า (มิฉะนั้นseq
จะคิดว่าเป็นส่วนหนึ่งของข้อกำหนดรูปแบบเช่น%f
); การใช้"${1//%/%%}"
จะดูแลที่ ตั้งแต่ (อย่างที่คุณพูดถึง) คุณกำลังใช้ BSD seq
นี้จะทำงานบน BSD เหมือนระบบปฏิบัติการทั่วไป (เช่น FreeBSD) - โดยคมชัดมันจะไม่ทำงานบนลินุกซ์ที่GNU seq
ถูกนำมาใช้
นี่คือสองวิธีที่น่าสนใจ:
ubuntu @ ubuntu: ~ $ yes = | หัว -10 | วาง -s -d '' - ========== ubuntu @ ubuntu: ~ $ yes = | หัว -10 | tr -d "\ n" ========== อูบุนตู @ อูบุนตู: ~ $
หมายเหตุทั้งสองนี้มีความแตกต่างกันเล็กน้อย - paste
วิธีสิ้นสุดในบรรทัดใหม่ tr
วิธีการไม่ได้
paste
อธิบายอย่างไม่ถูกต้อง-d '\0'
สำหรับการระบุตัวคั่นที่ว่างเปล่าและล้มเหลวด้วย-d ''
- -d '\0'
ควรทำงานด้วยการใช้งาน POSIX ที่เข้ากันได้ทั้งหมดpaste
และทำงานได้กับ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
ความพยายาม อย่างไรก็ตามที่สำคัญกว่านั้น: หากคุณกำลังใช้printf
อยู่คุณอาจใช้วิธีที่ง่ายและมีประสิทธิภาพมากขึ้นจากคำตอบที่ยอมรับ:printf '%.s=' $(seq 500)
ไม่มีวิธีง่ายๆ หลีกเลี่ยงการใช้ลูปprintf
และการแทนที่
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
repl = 100
ตัวอย่างเช่น (ไม่แสดงผลลัพธ์ต่อท้าย\n
):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
หากคุณต้องการความสอดคล้อง POSIX และความสอดคล้องในการใช้งานที่แตกต่างกันของecho
และprintf
และ / หรือเชลล์อื่นที่ไม่ใช่แค่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'
กับทุกที่
seq
ไม่ได้เป็นยูทิลิตี้ POSIX (แม้ว่าระบบ BSD และ Linux จะมีการใช้งาน) - คุณสามารถทำเลขคณิตเชลล์ POSIX ด้วยwhile
ลูปแทนได้ดังที่คำตอบของ @ Xennex81 ( printf "="
ตามที่คุณแนะนำถูกต้องมากกว่าecho -n
)
cal
POSIX คือ seq
ไม่ใช่. อย่างไรก็ตามแทนที่จะเขียนคำตอบใหม่อีกครั้งด้วยการวนรอบสักครู่ (อย่างที่คุณพูดนั่นคือคำตอบอื่น ๆ อยู่แล้ว) ฉันจะเพิ่มฟังก์ชั่น RYO วิธีการศึกษาเพิ่มเติม ;-)
คำถามคือทำอย่างไรกับecho
:
echo -e ''$_{1..100}'\b='
สิ่งนี้จะทำเช่นเดียวกันperl -E 'say "=" x 100'
กับที่มี แต่echo
เท่านั้น
วิธีทุบตีบริสุทธิ์โดยไม่ eval
, ไม่มี subshells, ไม่มีเครื่องมือภายนอก, ไม่มีการขยายรั้ง (เช่นคุณสามารถมีหมายเลขที่จะทำซ้ำในตัวแปร):
หากคุณได้รับตัวแปร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
varname
printf
จะใช้อาร์กิวเมนต์เพื่อพิมพ์จำนวนช่องว่างที่สอดคล้องกัน เช่นprintf '%*s' 42
จะพิมพ์ 42 ช่องว่าง${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}"
}
bash
การดำเนินการเปลี่ยนสตริงทั่วโลกในบริบทของการขยายพารามิเตอร์ ( ${var//old/new}
) ช้าโดยเฉพาะอย่างยิ่ง: ช้าทุบตีเลือดตาแทบกระเด็น3.2.57
และช้าทุบตี4.3.30
อย่างน้อยในระบบ OSX 10.10.3 ของฉันบนเครื่อง 3.2 Intel Core i5 3.2 Ghz: ด้วย จำนวน 1,000 สิ่งต่าง ๆ ช้า ( 3.2.57
) / เร็ว ( 4.3.30
): 0.1 / 0.004 วินาที การเพิ่มจำนวนถึง 10,000 ให้ผลต่างตัวเลขที่โดดเด่น: repeat 10000 = var
ใช้เวลาประมาณ 80 วินาที (!) ในการทุบตี3.2.57
และประมาณ 0.3 วินาทีในการทุบตี4.3.30
(เร็วกว่า3.2.57
มาก แต่ก็ยังช้า)
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
หรือ
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
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 }'; }
( จำเป็นต้องใช้.
คำนำหน้าdummy char และการsubstr
เรียกใช้เพิ่มเติมเพื่อแก้ไขข้อบกพร่องใน BSD awk
ซึ่งผ่านค่าตัวแปรที่เริ่มต้นด้วยการ=
แบ่งคำสั่ง)
NF = 100
แก้ปัญหาคือฉลาดมาก (แม้ว่าจะได้รับ 100 =
คุณต้องใช้NF = 101
) คำเตือนที่ว่ามันเกิดปัญหา BSD awk
( แต่มันเป็นไปอย่างรวดเร็วมากด้วยgawk
และเร็วยิ่งขึ้นด้วยmawk
) และที่กล่าวถึงใน POSIX ค่ากำหนดที่จะNF
ไม่ใช้เขตข้อมูลในBEGIN
บล็อก คุณสามารถทำให้มันทำงานใน BSD awk
ด้วยการปรับแต่งเล็กน้อย: awk 'BEGIN { OFS = "="; $101=""; print }'
(แต่อยากรู้อยากเห็นใน BSD awk
ที่ไม่เร็วกว่าสารละลายลูป) repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }
ในฐานะที่เป็นวิธีการแก้ปัญหาเปลือกแปร:
original-awk
คือชื่อภายใต้ Linux ของ awk รุ่นเก่าซึ่งคล้ายกับ awk ของ BSD ซึ่งได้รับการรายงานว่าล้มเหลวเช่นกันหากคุณต้องการลอง โปรดทราบว่าการหยุดทำงานมักเป็นขั้นตอนแรกในการค้นหาข้อบกพร่องที่สามารถใช้ประโยชน์ได้ คำตอบนี้ส่งเสริมรหัสที่ไม่ปลอดภัย
original-awk
ไม่ได้มาตรฐานและไม่แนะนำ
awk NF=100 OFS='=' <<< ""
(ใช้bash
และgawk
)
ฉันเดาว่าจุดประสงค์ดั้งเดิมของคำถามก็คือทำสิ่งนี้ด้วยคำสั่งในตัวของเชลล์ ดังนั้นfor
loops และprintf
s จะถูกต้องตามกฎหมายในขณะที่rep
, perl
และjot
ด้านล่างจะไม่ ยังคงคำสั่งดังต่อไปนี้
jot -s "/" -b "\\" $((COLUMNS/2))
ตัวอย่างเช่นพิมพ์บรรทัดกว้างของหน้าต่าง \/\/\/\/\/\/\/\/\/\/\/\/
jot -s '' -b '=' 100
ที่: ข้อแม้คือในขณะที่ BSD-เช่นแพลตฟอร์มรวมทั้ง OSX มาพร้อมกับjot
, distros ลินุกซ์ไม่ได้
apt install athena-jot
jot
ดังที่คนอื่น ๆ กล่าวไว้ในการขยาย bash braceนำหน้าการขยายพารามิเตอร์ดังนั้นช่วงสามารถมีได้เพียงตัวอักษรเท่านั้น และมอบโซลูชันที่สะอาด แต่ไม่สามารถพกพาได้อย่างสมบูรณ์จากระบบหนึ่งไปยังอีกระบบแม้ว่าคุณจะใช้เชลล์ตัวเดียวกันในแต่ละระบบ (แม้ว่าจะมีให้บริการเพิ่มมากขึ้นเช่นใน FreeBSD 9.3 และสูงกว่า ) และการอ้อมในรูปแบบอื่น ๆ มักจะใช้งานได้ แต่ไม่ค่อยมีความเหมาะสม{m,n}
seq
jot
seq
eval
โชคดีที่ทุบตีรองรับ C-style สำหรับลูป (ที่มีนิพจน์ทางคณิตศาสตร์เท่านั้น) ดังนั้นนี่คือวิธี "ทุบตีบริสุทธิ์" โดยย่อ:
repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
สิ่งนี้ใช้จำนวนการทำซ้ำเป็นอาร์กิวเมนต์แรกและสตริงที่จะทำซ้ำ (ซึ่งอาจเป็นอักขระเดียวเช่นเดียวกับในคำอธิบายปัญหา) เป็นอาร์กิวเมนต์ที่สอง repecho 7 b
เอาต์พุตbbbbbbb
(ถูกยกเลิกโดยขึ้นบรรทัดใหม่)
เดนนิสวิลเลียมสันให้เป็นหลักแก้ปัญหานี้สี่ปีที่ผ่านมาในคำตอบที่ดีเยี่ยมของเขาในการสร้างสายอักขระซ้ำในเชลล์สคริปต์ ฟังก์ชั่นร่างกายของฉันแตกต่างจากรหัสที่นั่นเล็กน้อย:
เนื่องจากมุ่งเน้นที่นี่อยู่ในการทำซ้ำตัวเดียวและเปลือกเป็นทุบตีมันอาจจะปลอดภัยที่จะใช้แทนecho
และผมอ่านคำอธิบายปัญหาที่เกิดขึ้นในคำถามนี้เช่นการแสดงการตั้งค่าการพิมพ์ด้วยprintf
echo
ความหมายของฟังก์ชั่นข้างต้นทำงานในทุบตีและksh93 แม้ว่าprintf
จะพกพาได้มากกว่า (และโดยปกติควรใช้กับสิ่งของประเภทนี้) แต่echo
ไวยากรณ์ของอ่านง่ายกว่า
บางหอยecho
builtins ตีความ-
ด้วยตัวเองเป็นตัวเลือก - แม้ว่าความหมายตามปกติของ-
การใช้ stdin echo
สำหรับการป้อนข้อมูลเป็นไร้สาระสำหรับ zshทำสิ่งนี้ และมีแน่นอนอยู่echo
ของที่ไม่รู้จัก-n
เป็นมันไม่ได้มาตรฐาน (กระสุนสไตล์ Bourne จำนวนมากไม่ยอมรับ C-style สำหรับลูปเลยดังนั้นecho
พฤติกรรมของพวกเขาไม่จำเป็นต้องพิจารณา .. )
ที่นี่งานคือการพิมพ์ลำดับ; ตรงนั้นมันเป็นการกำหนดให้ตัวแปร
หาก$n
เป็นจำนวนซ้ำที่ต้องการและคุณไม่ต้องใช้ซ้ำและคุณต้องการบางสิ่งที่สั้นกว่า:
while ((n--)); do echo -n "$s"; done; echo
n
ต้องเป็นตัวแปร - วิธีนี้ใช้ไม่ได้กับพารามิเตอร์ตำแหน่ง $s
เป็นข้อความที่จะต้องทำซ้ำ
printf "%100s" | tr ' ' '='
เหมาะสมที่สุด
zsh
ดีเช่นกัน วิธี echo-in-a-loop ทำงานได้ดีสำหรับจำนวนการทำซ้ำที่น้อยกว่า แต่สำหรับตัวที่ใหญ่กว่านั้นมีตัวเลือกที่สอดคล้องกับ POSIX บนพื้นฐานของยูทิลิตี้ตามความเห็นของ @ Slomojo
(while ((n--)); do echo -n "$s"; done; echo)
echo
-n
วิญญาณของสิ่งที่คุณพูดนั้นถูกต้องอย่างแน่นอน printf
ควรเป็นที่ต้องการecho
อย่างน้อยที่สุดในการใช้งานแบบไม่โต้ตอบ แต่ผมไม่คิดว่ามันเป็นไปในทางใด ๆ ที่ไม่เหมาะสมหรือทำให้เข้าใจผิดที่จะให้echo
คำตอบสำหรับคำถามที่ถามหาหนึ่งและที่ให้ข้อมูลเพียงพอที่จะรู้ว่ามันจะทำงาน โปรดทราบด้วยว่าการสนับสนุน((n--))
(โดยไม่มี$
) จะไม่รับประกันโดย POSIX
Python แพร่หลายและทำงานได้ทุกที่
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
ตัวละครและการนับจะถูกส่งเป็นพารามิเตอร์แยกต่างหาก
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
ใน bash 3.0 หรือสูงกว่า
for i in {1..100};do echo -n =;done
อีกวิธีหนึ่งในการทำซ้ำสตริงโดยพลการ n ครั้ง:
ข้อดี:
จุดด้อย:
yes
คำสั่งของ Gnu Core Utils#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
ด้วยเทอร์มินัล ANSI และอักขระ US-ASCII เพื่อทำซ้ำ คุณสามารถใช้ลำดับ escape ของ ANSI CSI มันเป็นวิธีที่เร็วที่สุดในการทำซ้ำตัวละคร
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
หรือแบบคงที่:
พิมพ์บรรทัด 80 ครั้ง=
:
printf '=\e[80b\n'
ข้อ จำกัด :
repeat_char
ลำดับ ANSI CSIrepeat_char
ลำดับ ANSI CSI เป็นอักขระซ้ำนี่คือสิ่งที่ฉันใช้พิมพ์บรรทัดของอักขระผ่านหน้าจอใน linux (ตามความกว้างของหน้าจอเทอร์มินัล / หน้าจอ)
printf '=%.0s' $(seq 1 $(tput cols))
คำอธิบาย:
พิมพ์เครื่องหมายเท่ากับหลาย ๆ ครั้งตามลำดับที่กำหนด:
printf '=%.0s' #sequence
ใช้เอาต์พุตของคำสั่ง (นี่คือคุณลักษณะทุบตีที่เรียกว่าการทดแทนคำสั่ง):
$(example_command)
ให้ลำดับฉันใช้ 1 ถึง 20 เป็นตัวอย่าง ในคำสั่งสุดท้ายคำสั่ง tput จะถูกใช้แทน 20:
seq 1 20
ระบุจำนวนคอลัมน์ที่ใช้ในเทอร์มินัลในปัจจุบัน:
tput cols
for i in {1..100}
do
echo -n '='
done
echo
repeat() {
# $1=number of patterns to repeat
# $2=pattern
printf -v "TEMP" '%*s' "$1"
echo ${TEMP// /$2}
}
ที่ง่ายที่สุดคือการใช้หนึ่งซับใน csh / tcsh นี้:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
ทางเลือกที่หรูหรากว่าสำหรับโซลูชัน Python ที่เสนออาจเป็น:
python -c 'print "="*(1000)'
ในกรณีที่คุณต้องการทำซ้ำตัวอักษร n ครั้งเป็น na จำนวนครั้งที่หลากหลายขึ้นอยู่กับความยาวของสตริงที่คุณสามารถทำได้:
#!/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})
; n=$(( 10 - ${#vari} ))
แต่ก็เรียบง่ายและมีประสิทธิภาพมากขึ้นเพื่อใช้ขยายตัวทางคณิตศาสตร์ของทุบตี: นอกจากนี้ที่หลักของคำตอบของคุณเป็นอย่างมากวิธี Perl ว่า OP ที่กำลังมองหาทุบตี ทางเลือกที่จะ
นี่เป็นเวอร์ชันที่ยาวกว่าของสิ่งที่ Eliah Kagan ได้รับมอบหมาย:
while [ $(( i-- )) -gt 0 ]; do echo -n " "; done
แน่นอนคุณสามารถใช้ printf สำหรับสิ่งนั้นได้เช่นกัน แต่ก็ไม่ได้ตามความชอบของฉัน:
printf "%$(( i*2 ))s"
เวอร์ชันนี้รองรับ Dash:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
โดยที่ฉันเป็นหมายเลขเริ่มต้น
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
}
ตัวอย่างการวิ่ง
$ repeatString 'a1' 10
a1a1a1a1a1a1a1a1a1a1
$ repeatString 'a1' 0
$ repeatString '' 10
อ้างอิง lib ที่: https://github.com/gdbtek/linux-cookbooks/blob/master/lไลบรารี/util.bash
ฉันจะทำสิ่งนี้ด้วยเสียงสะท้อนได้อย่างไร
คุณสามารถทำได้ด้วยecho
หากecho
มีการติดตามด้วยsed
:
echo | sed -r ':a s/^(.*)$/=\1/; /^={100}$/q; ba'
จริงๆแล้วecho
มันไม่จำเป็นเลย
คำตอบของฉันค่อนข้างซับซ้อนและอาจไม่สมบูรณ์แบบ แต่สำหรับผู้ที่ต้องการส่งออกจำนวนมากฉันสามารถทำประมาณ 10 ล้านใน 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}
}
ที่ง่ายที่สุดคือการใช้หนึ่งซับในทุบตี:
seq 10 | xargs -n 1 | xargs -I {} echo -n ===\>;echo
อีกตัวเลือกหนึ่งคือการใช้ GNU seq และลบหมายเลขและบรรทัดใหม่ทั้งหมดที่สร้าง:
seq -f'#%.0f' 100 | tr -d '\n0123456789'
คำสั่งนี้พิมพ์#
ตัวอักษร 100 ครั้ง
โซลูชันที่มีอยู่ส่วนใหญ่ทั้งหมดขึ้นอยู่กับ{1..10}
การสนับสนุนทางไวยากรณ์ของเชลล์ซึ่งเป็นbash
- และzsh
- เจาะจงและไม่ทำงานในtcsh
หรือ OpenBSD's ksh
และ non-bash ส่วนใหญ่sh
และส่วนใหญ่ไม่ใช่ทุบตี
ข้อมูลต่อไปนี้ควรใช้กับ OS X และระบบ * BSD ทั้งหมดในเชลล์ใด ๆ ในความเป็นจริงมันสามารถใช้ในการสร้างเมทริกซ์พื้นที่ตกแต่งประเภทต่างๆ:
$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$
น่าเศร้าที่เราไม่ได้ขึ้นบรรทัดใหม่ ซึ่งสามารถแก้ไขได้โดยการเสริมprintf '\n'
หลังจากการพับ:
$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$
อ้างอิง:
ข้อเสนอของฉัน (ยอมรับค่าตัวแปรสำหรับ n):
n=100
seq 1 $n | xargs -I {} printf =