ฉันจะสร้างสคริปต์ให้นับด้วยห้าคนได้อย่างไร


10

ฉันพยายามสร้างสคริปต์ทุบตีที่ง่ายมากเพื่อแสดงรายการทวีคูณของห้าทั้งหมดระหว่าง 375 และ 3500 (375, 380, 385 ... ) สิ่งหนึ่งที่ฉันพยายามและไม่ได้ผลคือ:

for i in {375..3500}
do
        echo $i
        (($i += 5))
done

ฉันสละเวลาสักครู่แล้วเขียนมันในภาษาเบสิกในเวลาประมาณ 15 วินาที:

10 count = 375
20 print count
30 count = count+5
40 if count < 3500 then goto 20

ฉันจะทำให้โปรแกรม BASIC เป็นสคริปต์ทุบตีได้อย่างไร


สิ่งนี้จะดีกว่าเมื่อมีการล้นสแต็ก - Unix & Linux เกี่ยวกับระบบปฏิบัติการไม่ใช่การเข้ารหัส การเข้ารหัสมีไว้สำหรับ stackoverflow
noɥʇʎԀʎzɐɹƆ

คำตอบ:


20

หรือจะใช้สไตล์ C แบบดั้งเดิมสำหรับลูปก็ได้:

for ((i=375; i<=3500; i+=5)); do
    echo $i
done

นี่อาจจะชัดเจนน้อยกว่าการใช้ seq แต่จะไม่วางไข่การประมวลผลใด ๆ แม้ว่าฉันจะคุ้นเคยกับ C ฉันก็ไม่ยากที่จะเข้าใจสิ่งนี้ แต่เป็น YMMV


1
ข้อเสียของวิธีนี้คือมันพกพาได้น้อยกว่า วิธีการ seq ทำงานใน POSIX sh
Wouter Verhelst

โอ้, C-style สำหรับลูปไม่มีอยู่ใน POSIX sh หรือไม่? คุณได้เรียนรู้สิ่งใหม่ทุกวัน ...
35470

2
@WouterVerhelst ดียกเว้นถ้าคุณถูก จำกัด POSIX sh คุณไม่น่าจะมี seq ซึ่งเป็นส่วนหนึ่งของ coreutils ของ GNU busybox มีการนำไปใช้ที่ จำกัด มากขึ้น แต่นอกเหนือจากนั้นระบบฝังตัวจำนวนมากอาจไม่สามารถใช้งานได้เลย
Chris Down

1
@Muzer - อย่างน้อยdashไม่รองรับ @ChrisDown - ไม่มีเหตุผลว่าทำไม "POSIX ดวลจุดโทษ" ไม่ได้มีที่จะบ่งบอกว่า "ไม่ seq" แต่ใช่ฉันได้มองข้ามความจริงที่ว่า POSQ ไม่ได้ระบุไว้
Wouter Verhelst

27

เนื่องจากคุณใช้ส่วนขยายรั้งอยู่แล้วใช้ประโยชน์จากคุณลักษณะอย่างเต็มที่:

echo {375..3500..5}

คุณยังสามารถใช้เทคนิคนี้เพื่อพิมพ์แต่ละหมายเลขในบรรทัดแยกกันด้วยข้อความเพิ่มเติมโดยใช้printfแทนechoตัวอย่างเช่น:

$ printf "Number %s is generated.\n" {375..3500..5}
Number 375 is generated.
Number 380 is generated.
Number 385 is generated.
...

แก้ไข

ตามที่ระบุโดย @kojiro ในข้อคิดเห็นของ Mac OS ใช้ bash 3 เป็นเชลล์เริ่มต้นซึ่งไม่สนับสนุนการเพิ่มขึ้นของนิพจน์ลำดับของการขยายรั้ง คุณต้องอัปเกรดเป็นทุบตีเวอร์ชัน 4 หรือใช้เชลล์อื่นที่รองรับ (เช่น zsh ล่าสุด)


2
สิ่งนี้ใช้ไม่ได้กับฉันใน Mac OS 10.10.3 ส่งเอาต์พุต '{375..3500..5}'
เช่น

6
@ aswine นั่นเป็นเหตุผลที่คุณควรพูดถึงระบบปฏิบัติการของคุณเสมอเมื่อถาม โดยเฉพาะอย่างยิ่งตั้งแต่ OSX มีความแตกต่างจำนวนมากทั้งจาก UNICE อื่นและจาก Linux
terdon

2
นี่ไม่ใช่ความแตกต่างของระบบปฏิบัติการต่อ se มันเป็นความแตกต่างของรุ่น OS X มีเพียง BASH 3 OOTB คุณสามารถติดตั้ง BASH จากศตวรรษนี้โดยใช้ตัวจัดการแพคเกจ OS X เกือบทุกเครื่อง ฉันใช้ Home Brew หนึ่งอัน
kojiro

2
ความจริงที่ว่าการขยายตัวนั้นล้มเหลวในการทำงานโดยตรง แต่ประสบความสำเร็จในbash -cการรับประกันว่าเชลล์ที่แตกต่างกันสองอันเกี่ยวข้องกัน ไม่$SHELL --versionบอกว่ามันทุบตี 3 หรือไม่?
dhag

3
@mikeserv คำตอบนั้นง่ายมาก - ฉันไม่ได้เขียนเพราะฉันไม่รู้ว่าbashฟีเจอร์นี้ของเวอร์ชันไหนถูกนำเสนอ ฉันได้เรียนรู้ด้วยตัวเองจากความคิดเห็น kojiro และโปรดอย่าเปรียบเทียบฉันกับเซาท์แคโรไลนาฉันไม่ทราบรายละเอียดและประวัติของกระสุนทั้งหมดตั้งแต่ปลายปี 1970 อีกครั้ง - ถ้าคุณคาดหวังว่าคุณแค่ downvote
jimmij


11

ตัวอย่างข้อมูลแบบลูปของคุณไม่ทำงานตามที่คุณต้องการด้วยเหตุผลสองประการ:

  • (($i += 5))- ที่นี่มีการขยายค่าของ$i iดังนั้นการขยายตัวจะเป็นสิ่ง((375 += 5))ที่ไม่เหมาะสม (พยายามกำหนดจำนวนตัวอักษรให้กับตัวอักษรอื่น) โดยปกติจะทำได้ด้วย((i += 5))(ไม่$ต้องขยายตัวแปร)
  • {375..3500}จะขยายก่อนซ้ำแรกของวง 375 376 ... 3499 3500มันจะเป็นรายการของตัวเลข สำหรับการวนซ้ำแต่ละครั้งiจะได้รับการกำหนดให้กับแต่ละหมายเลขเหล่านี้หนึ่งต่อหนึ่ง ดังนั้นในตอนเริ่มต้นของการทำซ้ำแต่ละครั้งiจะถูกกำหนดใหม่ให้กับค่าถัดไปในรายการนั้นนับขึ้นในขั้นตอนที่ 1 การ((i += 5))ทำอะไรที่มีประสิทธิภาพไม่ได้ - มันเพิ่ม 5 ถึง i แต่จากนั้นฉันเพิ่งกำหนดใหม่อีกครั้งเมื่อเริ่ม การทำซ้ำครั้งต่อไป

ฉันคิดว่าฉันชอบfor (( ; ; ))คำตอบที่ดีที่สุด แต่นี่เป็นทางเลือกที่จะทำให้คุณคิด:


เนื่องจากเรากำลังติดต่อกับทวีคูณของ 5 และการ{a..b..i}ขยายตัวไม่รองรับใน bash เวอร์ชั่น 3.2.57 (1) (ใน OS X) จากนั้นเราสามารถทำสิ่งที่มีความลับเล็กน้อยแทน:

for i in 375 {38..349}{0,5} 3500; do
    echo $i
done

นี่แสดงให้เห็นถึงวิธีการทุบตีสามารถใช้ในการสร้างผลิตภัณฑ์คาร์ทีเซียน


ฉันคิดว่าโดยทั่วไป a for loop เป็นวิธีที่สะดวกที่สุดในการทำสิ่งนี้ แต่ถ้าคุณสนใจคุณสามารถใช้ while-loop (ใกล้กับ BASIC ของคุณมากขึ้น):

count=375
while (( count <= 3500 )); do
    echo $count
    (( count += 5 ))
done

1
@jimmij ... ผลิตภัณฑ์คาร์ทีเซียนคืออะไร คุณสามารถลงคะแนนความคิดเห็นหากคุณต้องการและฉันจะไม่สนใจถ้าคุณบอกฉัน ฉันอยากรู้.
mikeserv

1
@mikeserv คุณไม่สามารถลงคะแนนความคิดเห็น: en.wikipedia.org/wiki/Cartesian_product
jimmij

@jimmij - มันยังโอเคกับฉันถ้าคุณทำ
mikeserv

@jimmij ปีศาจที่คุณพูดถึงคืออะไร? ผลิตภัณฑ์คาร์ทีเซียนคือชุดของ tuples ของชุดค่าผสมที่เป็นไปได้ทุกชุดจากสองชุด (ซึ่งอาจเป็นชุดเดียวกันหรือไม่ก็ได้) ยิ่งเรียกขานมันเป็น "ชุดค่าผสมที่เป็นไปได้ทั้งหมด" จากสองกลุ่มของสิ่งต่าง ๆ ฉันเห็นเพียงชุดเดียว มีสินค้าคาร์ทีเซียนที่นี่ได้อย่างไร?
jpmc26

1
@ jpmc26 ถูกต้องมันคือ "ชุดค่าผสมที่เป็นไปได้ทั้งหมด" ดังนั้นให้พล็อตสองแกน - โดยเริ่มจากเขียนตัวเลขทั้งหมดตั้งแต่ต้น38จน349จบ ในวันที่สองเพียงสองหมายเลข: และ0 5ตอนนี้ให้สร้างคู่ได้รับคำสั่งของผู้ที่อยู่รวมกันทั้งหมด - คุณสามารถเขียนพวกเขาเป็นชุด: {38,0}, {38,5}... {349,5}หรือเพียงแค่ลบสัญลักษณ์ซ้ำซ้อน{, ,และ}และได้รับ ... ตัวเลขใหม่...380 3495
jimmij

5

ในขณะที่มีแน่นอนแอปสำหรับ ( seq 375 5 3500) นั้นมีหลายวิธีในการทำเช่นนี้จาก commandline ในขณะที่การใช้งานที่เร็วและง่ายที่สุดseqนี่คือตัวเลือกอื่น ๆ :

for i in {375..3500}; do [[ (($i % 5)) -eq 0 ]] && echo $i; done

i=370; while [ $i -le 3500 ]; do printf "%s\n" $((i+=5)); done

perl -le '$i=shift;while($i<=$ARGV[0]){print $i; $i+=5; }' 375 3500
perl -le 'map{print $_ + 5} 370..3495'

awk 'BEGIN{ for(i=375;i<=3500;i+=5){print i}}'

เลือก Nit: $(($i % 5))สามารถเขียน$((i % 5))ได้
G-Man กล่าวว่า 'Reinstate Monica'

4

POSIXly:

i=370
while [ 3500 -gt "$i" ]
do    echo "$((i+=5))"
done

...หรือ...

echo 'for(x=370;x<=3500;x+=5)x' |bc

ฉันไม่รู้ว่าทำไมคุณถึงทำอย่างอื่น ยกเว้นแน่นอน ...

seq 375 5 3500

... หรือกับdc:

echo '370[5+pd3500>p]splpx'|dc

ฉันอยากรู้ว่าdcโค้ดทำงานอย่างไร seqมันแน่นอนมากขึ้นน่าสนใจกว่าการใช้
dhag

1
@dhag - มันเขียนลูปเล็กน้อย มันsaves [สตริง]ที่ด้านบนของpอาร์เรย์จากนั้นloads มันกลับสู่ด้านบนของสแต็คและ e xecutes มันเป็นแมโคร ภายในมาโครเรากด5บนสแต็กจากนั้นป๊อปอัพและที่สองจากด้านบนและ+พวกเขาแทนที่ค่าสแต็กทั้งสองด้วยผลรวมของพวกเขาซึ่งเป็นprinted และduplicated ก่อนที่3500จะผลักดันสแต็คเมื่อเราปรากฏมันและล่อ >การเปรียบเทียบ หาก3500มีขนาดใหญ่กว่าเราจะโหลดและเรียกใช้งานเป็นมาโครที่เก็บไว้ในpอาร์เรย์(มาโครปัจจุบันของเรา)หรือถ้าไม่แตก
mikeserv

3

หากคุณติดอยู่ที่ Bash 3:

echo {375..3500} | tr ' ' '\n' | sed -n 'p;n;n;n;n'

และหากคุณต้องการawk:

echo {375..3500} | tr ' ' '\n' | awk '!((NR-1)%5)'

ฉันไม่รู้เกี่ยวกับการขยายรั้ง - มันเจ๋งมาก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.