มีคำสั่ง unix ที่ให้จำนวนขั้นต่ำ / สูงสุดของสองตัวเลข?


37

stdinผมกำลังมองหาคำสั่งไปยังหมายเลขวงเงินอ่านในจาก

ฉันเขียนสคริปต์เล็กน้อยเพื่อจุดประสงค์นั้น (ยินดีต้อนรับคำติชม) แต่ฉันสงสัยว่าถ้าไม่มีคำสั่งมาตรฐานสำหรับเรื่องนี้ง่ายและ (ฉันคิดว่า) กรณีการใช้งานทั่วไป

สคริปต์ของฉันซึ่งค้นหาอย่างน้อยสองตัวเลข:

#!/bin/bash
# $1 limit

[ -z "$1" ] && { echo "Needs a limit as first argument." >&2; exit 1; }

read number

if [ "$number" -gt "$1" ]; then
        echo "$1"
else
        echo "$number"
fi

คำตอบ:


20

คุณสามารถเปรียบเทียบตัวเลขเพียงสองตัวกับdclike:

dc -e "[$1]sM $2d $1<Mp"

... ที่"$1"คุ้มค่าสูงสุดของคุณและเป็นจำนวนที่คุณพิมพ์ถ้ามันเป็นน้อยกว่า"$2" "$1"สิ่งนี้ต้องการ GNU ด้วยdcเช่นกัน แต่คุณสามารถทำสิ่งเดียวกันนี้ได้เช่น:

dc <<MAX
    [$1]sM $2d $1<Mp
MAX

ในทั้งสองกรณีข้างต้นคุณสามารถตั้งค่าความแม่นยำอย่างอื่นที่ไม่ใช่ 0 (เริ่มต้น)${desired_precision}kเช่น คุณจำเป็นต้องตรวจสอบว่าทั้งสองค่านั้นเป็นตัวเลขแน่นอนเพราะdcสามารถทำการsystem()โทรด้วยตัว!ดำเนินการ

ด้วยสคริปต์เล็ก ๆ น้อย ๆ ต่อไปนี้(และถัดไป)คุณควรตรวจสอบอินพุตเหมือนgrep -v \!|dcหรือบางสิ่งบางอย่างเพื่อจัดการอินพุตโดยพลการ คุณควรรู้ด้วยว่าdcการตีความตัวเลขลบด้วย_คำนำหน้าแทนที่จะเป็นส่วน-นำหน้า - เพราะตัวเลขหลังเป็นตัวดำเนินการลบ

นอกเหนือจากนั้นสคริปต์นี้dcจะอ่าน\nตัวเลขที่คั่นด้วย ewline ตามจำนวนที่คุณต้องการให้และพิมพ์สำหรับแต่ละ$maxค่าหรืออินพุตของคุณขึ้นอยู่กับว่าอะไรคือ wo:

dc -e "${max}sm
       [ z 0=? d lm<M p s0 lTx ]ST
       [ ? z 0!=T q ]S?
       [ s0 lm ]SM lTx"

ดังนั้น ... แต่ละคน[วงเล็บตาราง]กว้างใหญ่เป็นdc สตริงวัตถุที่ถูกSaved แต่ละอาร์เรย์ของแต่ละ - หนึ่งใด ๆT, หรือ? Mนอกจากนี้บางสิ่งอื่น ๆdcอาจทำกับสตริงมันยังสามารถxหนึ่ง ecute เป็นแมโคร หากคุณจัดเรียงให้ถูกต้องdcสคริปต์ตัวเล็กที่ทำงานได้อย่างสมบูรณ์จะถูกประกอบเข้าด้วยกันอย่างเพียงพอ

dcทำงานบนสแต็ก วัตถุอินพุตทั้งหมดจะซ้อนกันในช่วงสุดท้าย - แต่ละวัตถุอินพุตใหม่ผลักวัตถุชั้นนำสุดท้ายและวัตถุทั้งหมดด้านล่างลงบนสแต็กโดยหนึ่งเมื่อมีการเพิ่ม อ้างอิงส่วนใหญ่ไปยังวัตถุที่มีค่าที่สแต็คด้านบนและการอ้างอิงมากที่สุดปรากฏด้านบนของสแต็คที่(ซึ่งจะดึงวัตถุทั้งหมดที่อยู่ด้านล่างขึ้นโดยหนึ่ง)

นอกเหนือจากสแต็กหลักยังมี(อย่างน้อย) 256 อาร์เรย์และแต่ละองค์ประกอบอาเรย์จะมาพร้อมกับสแต็กทั้งหมดของตัวเอง ฉันไม่ได้ใช้สิ่งเหล่านี้ที่นี่ ฉันเพียงแค่เก็บสายดังกล่าวเพื่อให้สามารถlOAD พวกเขาเมื่อต้องการและ e xecute พวกเขามีเงื่อนไขและผมsฉีก$max's ค่าในด้านบนของmอาร์เรย์

อย่างไรก็ตามสิ่งเล็กน้อยนี้dcทำส่วนใหญ่เชลล์สคริปต์ของคุณทำอะไร มันใช้-eตัวเลือกGNU-ism dcโดยทั่วไปจะใช้พารามิเตอร์จากมาตรฐานใน - แต่คุณสามารถทำเช่นเดียวกัน:

echo "$script" | cat - /dev/tty | dc

... ถ้า$scriptดูเหมือนบิตด้านบน

มันทำงานเหมือน:

  • lTx- นี่loads และ e xecutes แมโครที่เก็บไว้ในด้านบนของT (สำหรับการทดสอบผมคิดว่า - ฉันมักจะเลือกชื่อเหล่านั้นพล)
  • z 0=?- Test จะทำการทดสอบความลึกของสแต็กที่มีzและหากสแต็กเตอร์ว่างเปล่า(read: ถือ 0 วัตถุ)มันจะเรียก?มาโคร
  • ? z0!=T q- ?แมโครถูกตั้งชื่อสำหรับ? dcคำสั่ง builtin ซึ่งอ่านบรรทัดอินพุตจาก stdin แต่ฉันยังเพิ่มzการทดสอบความลึกสแต็กอีกครั้งเพื่อให้สามารถqใช้โปรแกรมเล็ก ๆ น้อย ๆ ทั้งหมดถ้ามันดึงในบรรทัดว่างหรือกด EOF แต่ถ้ามัน!ไม่สำเร็จและแทนการเติมสแต็กสำเร็จจะเรียกว่าTest อีกครั้ง
  • d lm<M- Tคือจะduplicate ด้านบนของสแต็คและเปรียบเทียบกับ$max (ตามที่เก็บไว้ในm ) ถ้าmเป็นค่าที่น้อยกว่าให้dcเรียกMแมโคร
  • s0 lm- Mเพียงแค่โผล่ที่ด้านบนของสแต็กและทิ้งไปที่เซนต์คิตส์และเนวิส0- เพียงวิธีที่ถูกกอง popping นอกจากนี้ยังมีการlโหลดmอีกครั้งก่อนกลับไปที่Test
  • p- ซึ่งหมายความว่าหากmน้อยกว่าด้านบนสุดของสแต็กปัจจุบันจากนั้นmแทนที่มัน( duplicate ของมันต่อไป)และอยู่ที่นี่printed อื่นมันไม่ได้และสิ่งที่ใส่เป็นprinted แทน
  • s0- หลังจากนั้น(เพราะpจะไม่ปรากฏสแต็ค)เราจะทำการถ่ายโอนด้านบนของสแต็กเข้าไป0อีกครั้งแล้ว ...
  • lTx- ซ้ำlOAD Tคืออีกครั้งแล้วอีxecute มันอีกครั้ง

ดังนั้นคุณสามารถเรียกใช้ตัวอย่างข้อมูลเล็ก ๆ นี้และพิมพ์ตัวเลขแบบโต้ตอบได้ที่เทอร์มินัลของคุณและdcจะพิมพ์กลับมาที่คุณทั้งหมายเลขที่คุณป้อนหรือมูลค่า$maxถ้าจำนวนที่คุณพิมพ์มีขนาดใหญ่ขึ้น มันจะยอมรับไฟล์ใด ๆ(เช่นไพพ์)เป็นอินพุตมาตรฐาน มันจะดำเนินการอ่าน / เปรียบเทียบ / พิมพ์ห่วงจนกว่าจะพบบรรทัดว่างหรือ EOF

หมายเหตุบางอย่างเกี่ยวกับเรื่องนี้ - ฉันเขียนสิ่งนี้เพื่อเลียนแบบพฤติกรรมในฟังก์ชันเชลล์ของคุณดังนั้นมันจึงจัดการหมายเลขหนึ่งต่อบรรทัดได้อย่างสมบูรณ์เท่านั้น dcอย่างไรก็ตามสามารถจัดการหมายเลขที่คั่นด้วยช่องว่างต่อบรรทัดได้มากเท่าที่คุณต้องการจะโยน อย่างไรก็ตามเนื่องจากสแต็กเป็นจำนวนสุดท้ายในบรรทัดจะเป็นคนแรกที่ทำงานและดังนั้นตามที่เขียนไว้dcจะพิมพ์เอาต์พุตในทางกลับกันถ้าคุณพิมพ์ / พิมพ์มากกว่าหนึ่งหมายเลขต่อหนึ่งบรรทัดวิธีที่เหมาะสม เพื่อจัดการนั่นคือการจัดเก็บบรรทัดในอาร์เรย์จากนั้นทำงาน

แบบนี้:

dc -e "${max}sm
    [ d lm<M la 1+ d sa :a z0!=A ]SA
    [ la d ;ap s0 1- d sa 0!=P ]SP 
    [ ? z 0=q lAx lPx l?x ]S?
    [q]Sq [ s0 lm ]SM 0sa l?x"

แต่ ... ฉันไม่รู้ว่าฉันต้องการอธิบายเรื่องนี้ในเชิงลึกมากน้อยแค่ไหน เพียงพอที่จะบอกว่าเมื่อdcอ่านค่าแต่ละค่าบนสแต็กมันจะเก็บค่าหรือค่า$maxของมันในอาเรย์ที่จัดทำดัชนีและเมื่อตรวจพบสแต็กจะว่างเปล่าอีกครั้งจากนั้นก็พิมพ์วัตถุแต่ละดัชนี สายของอินพุต

และในขณะที่สคริปต์แรกทำ ...

10 15 20 25 30    ##my input line
20
20
20
15
10                ##see what I mean?

ที่สองทำ:

10 15 20 25 30    ##my input line
10                ##that's better
15
20
20                ##$max is 20 for both examples
20

คุณสามารถจัดการลอยของความแม่นยำโดยพลการถ้าคุณตั้งค่าด้วยkคำสั่ง และคุณสามารถปรับเปลี่ยนinput หรือoutices radices อย่างอิสระซึ่งบางครั้งอาจมีประโยชน์สำหรับเหตุผลที่คุณอาจไม่คาดคิด ตัวอย่างเช่น:

echo 100000o 10p|dc
 00010

... ชุดแรกdcที่ส่งออก radix ถึง 100,000 แล้วพิมพ์ 10


3
+1 ที่ไม่รู้ว่าเกิดอะไรขึ้นหลังจากอ่านสองครั้ง จะต้องใช้เวลาของฉันในการเจาะลึกเรื่องนี้
Minix

@ Minix - meh - ไม่จำเป็นต้องไปศึกษาภาษา Unix ที่เก่าแก่ที่สุดหากคุณพบว่ามันสับสน บางทีอาจเป็นเพียงการส่งข้อมูลจำนวนน้อยdcครั้งละครั้งในชั่วขณะหนึ่งเพื่อเก็บไว้ในนิ้วเท้า
mikeserv

1
@mikeserv มันสายเกินไปสำหรับฉัน ฉันหวังว่าคนรุ่นต่อไปจะใช้เวลาของฉันเป็นเรื่องเตือน วงเล็บเหลี่ยมและตัวอักษรทุกที่ ...
ซ์

@ Minix - คุณหมายถึงอะไร? คุณไปเพื่อมัน ดีมาก - dcเป็นสัตว์ร้าย แต่ก็อาจเป็นยูทิลิตีทั่วไปที่เร็วที่สุดและมีความสามารถมากที่สุดในระบบ Unix เมื่อจับคู่ w / sedมันสามารถทำสิ่งที่พิเศษ ฉันได้รับเล่นกับมันและddเมื่อเร็ว ๆ readlineนี้เพื่อที่ฉันอาจแทนที่ประหลาดที่ นี่คือตัวอย่างเล็ก ๆของสิ่งที่ฉันได้ทำ ทำrevในdcเกือบจะเป็นของเด็กเล่น
mikeserv

1
@ Minix - ระวัง w / วงเล็บด้วย ไม่มีทางที่จะใส่วงเล็บเหลี่ยมภายในสตริงไม่ได้ - [string]P91P93P[string]Pที่ดีที่สุดที่คุณสามารถทำได้คือ ดังนั้นฉันมีคุณเล็กน้อยนี้sedอาจพบว่ามีประโยชน์: sed 's/[][]/]P93]&[1P[/g;s/[]3][]][[][1[]//g'ซึ่งควรแทนที่สี่เหลี่ยมอย่างถูกต้องด้วยวงเล็บปิดสตริงแล้ว a P, จากนั้นค่าทศนิยม ASCII ของตารางและอีกP; จากนั้น[วงเล็บเหลี่ยมเปิดเพื่อดำเนินการกับสตริง Dunno ถ้าคุณทำข้อผิดพลาดรอบ ๆ ด้วยdcความสามารถในการแปลงสตริง / ตัวเลข แต่โดยเฉพาะอย่างยิ่งเมื่อรวมกันด้วยod- อาจเป็นเรื่องสนุก
mikeserv

88

หากคุณรู้ว่าคุณกำลังเผชิญกับจำนวนเต็มสองจำนวนaและbจากนั้นการคำนวณทางคณิตศาสตร์ของเชลล์แบบง่ายเหล่านี้โดยใช้ตัวดำเนินการแบบไตรภาคจะเพียงพอที่จะให้ค่าตัวเลขสูงสุด:

$(( a > b ? a : b ))

และนาทีเป็นตัวเลข:

$(( a < b ? a : b ))

เช่น

$ a=10
$ b=20
$ max=$(( a > b ? a : b ))
$ min=$(( a < b ? a : b ))
$ echo $max
20
$ echo $min
10
$ a=30
$ max=$(( a > b ? a : b ))
$ min=$(( a < b ? a : b ))
$ echo $max
30
$ echo $min
20
$ 

นี่คือเชลล์สคริปต์ที่แสดงสิ่งนี้:

#!/usr/bin/env bash
[ -z "$1" ] && { echo "Needs a limit as first argument." >&2; exit 1; }
read number
echo Min: $(( $number  < $1 ? $number : $1 ))
echo Max: $(( $number  > $1 ? $number : $1 ))

คำตอบที่ดี โปรดใช้ตัวดัดแปลงเล็กน้อย: สามารถใช้กับ "> =" ได้หรือไม่
Sopalajo de Arrierez

@SopalajodeArrierez ฉันไม่แน่ใจว่าคุณหมายถึงอะไร คุณสามารถทำได้max=$(( a >= b ? a : b ))แต่ผลลัพธ์จะเหมือนกันโดยสิ้นเชิง - ถ้า a และ b เท่ากันมันก็ไม่สำคัญว่าจะคืนค่าใด นั่นคือสิ่งที่คุณถาม
Digital Trauma

แน่นอนว่าต้องขอบคุณ DIgital Trauma ฉันแค่สงสัยว่าตัวดำเนินการบูลีน "> =" เป็นไปได้หรือไม่
Sopalajo de Arrierez

@SopalajodeArrierez if (( a >= b )); then echo a is greater than or equal to b; fi- นั่นคือสิ่งที่คุณต้องการหรือ (โปรดสังเกตการใช้(( ))ที่นี่แทน$(( )))
Digital Trauma

อ่าใช่แล้ว ฉันเข้าใจแล้ว. ฉันไม่ค่อยรู้เรื่องการขยายตัวของเชลล์ดังนั้นฉันมักจะสับสนระหว่างเงื่อนไข ขอบคุณอีกครั้ง
Sopalajo de Arrierez

25

sortและheadสามารถทำสิ่งนี้:

numbers=(1 4 3 5 7 1 10 21 8)
printf "%d\n" "${numbers[@]}" | sort -rn | head -1       # => 21

2
หมายเหตุว่านี่คือในขณะที่การดำเนินงานที่มีประสิทธิภาพของแม็กซ์จะเป็นO(n log(n)) O(n)มันมีความสำคัญเพียงเล็กน้อยของเราคือn=2แม้ว่าเนื่องจากการวางไข่ของทั้งสองกระบวนการมีค่าใช้จ่ายที่ใหญ่กว่ามาก
Lie Ryan

1
ในขณะที่เป็นจริง @ glenn-jackman ฉันไม่แน่ใจว่ามันสำคัญสำหรับคำถาม ไม่มีการร้องขอวิธีที่มีประสิทธิภาพที่สุดในการดำเนินการ ฉันคิดว่าคำถามเกี่ยวกับความสะดวกสบายมากขึ้น
David Hoelzer

1
@DavidHoelzer - นี่ไม่ใช่วิธีที่มีประสิทธิภาพที่สุดในการทำสิ่งนี้แม้จะเป็นคำตอบก็ตาม ถ้าทำงานร่วมกับชุดจำนวนมีอย่างน้อยหนึ่งคำตอบอื่น ๆ ที่นี่ที่มีประสิทธิภาพมากขึ้นกว่านี้(โดยคำสั่งของขนาด)และถ้าเพียง แต่การทำงานกับจำนวนเต็มสองจำนวนมีคำตอบที่นี่อีกที่มีประสิทธิภาพมากขึ้นกว่าที่(โดยคำสั่งของขนาด) แม้ว่ามันเป็นความสะดวกสบาย( แต่ผมก็อาจจะออกจากอาร์เรย์เปลือกส่วนตัว)
mikeserv

1
สามารถทำได้โดยไม่ต้องใช้อาร์เรย์ดังนี้:numbers="1 4 3 5 7 1 10 21 8"; echo $numbers | tr ' ' "\n" | sort -rn | head -n 1
ngreen

1
วิธีการที่มีประสิทธิภาพมากขึ้นอาจนี้คือ:max=0; for x in $numbers ; do test $x -gt $max && max=$x ; done
ngreen

6

คุณสามารถกำหนดไลบรารีของฟังก์ชันคณิตศาสตร์ที่กำหนดไว้ล่วงหน้าbcแล้วใช้ในบรรทัดคำสั่ง

ตัวอย่างเช่นรวมสิ่งต่อไปนี้ในไฟล์ข้อความเช่น~/MyExtensions.bc:

define max(a,b){
  if(a>b)
  { 
   return(a)
  }else{
   return(b)
  }
}

ตอนนี้คุณสามารถโทรbcโดย:

> echo 'max(60,54)' | bc ~/MyExtensions.bc
60

FYI มีฟังก์ชั่นห้องสมุดคณิตศาสตร์ฟรีเช่นที่มีอยู่ออนไลน์

เมื่อใช้ไฟล์นั้นคุณสามารถคำนวณฟังก์ชันที่ซับซ้อนได้ง่ายขึ้นเช่นGCD:

> echo 'gcd (60,54)' | bc ~/extensions.bc -l
6

ถ้าฉันไม่ผิดฟังก์ชั่นดังกล่าวยังสามารถรวบรวมกับปฏิบัติการถ้าจำเป็น ผมคิดว่าส่วนใหญ่bcs เป็นเพียงdcส่วนหน้าไปในวันนี้แม้ว่าแม้ว่าGNUbcไม่มีอีกต่อไปเช่น( แต่ GNU dcและ GNU bcหุ้นเป็นจำนวนเงินมหาศาล codebase พวกเขา) อย่างไรก็ตามนี่อาจเป็นคำตอบที่ดีที่สุดที่นี่
mikeserv

หากต้องการเรียกสิ่งนี้อย่างสะดวกภายในไฟล์ของเชลล์สคริปต์คุณสามารถไพพ์ในการกำหนดฟังก์ชันได้bcเช่นกันก่อนการเรียกฟังก์ชัน ไม่จำเป็นต้องมีไฟล์ที่สอง :)
tanius

5

ยาวเกินไปสำหรับความคิดเห็น:

ในขณะที่คุณสามารถทำสิ่งเหล่านี้เช่นกับคอมโบsort | headหรือsort | tailมันดูเหมือนว่าทั้งทรัพยากรและข้อผิดพลาดการจัดการฉลาด เท่าที่เกี่ยวข้องกับการดำเนินการคำสั่งผสมหมายถึงการวางไข่ 2 กระบวนการเพียงเพื่อตรวจสอบสองบรรทัด ที่ดูเหมือนจะเป็นบิตของ overkill

ปัญหาที่ร้ายแรงกว่านั้นคือในกรณีส่วนใหญ่คุณจำเป็นต้องรู้ว่าอินพุตนั้นมีสติซึ่งประกอบด้วยตัวเลขเท่านั้น วิธีการแก้ปัญหาของ @ glennjackmannชาญฉลาดแก้ปัญหานี้เนื่องจากprintf %dควร barf กับไม่ใช่จำนวนเต็ม มันจะไม่ทำงานกับการลอยตัว (เว้นแต่คุณจะเปลี่ยนตัวระบุรูปแบบเป็น%fที่ซึ่งคุณจะพบปัญหาการปัดเศษ)

test $1 -gt $2 จะให้คุณระบุว่าการเปรียบเทียบล้มเหลวหรือไม่ (สถานะออกจาก 2 หมายความว่ามีข้อผิดพลาดระหว่างการทดสอบเนื่องจากนี่เป็นเชลล์ในตัวจึงไม่มีกระบวนการเพิ่มเติมเกิดขึ้น - เรากำลังพูดถึงคำสั่งหลายร้อยรายการ เวลาในการประมวลผลที่เร็วขึ้นใช้ได้กับจำนวนเต็มเท่านั้น

หากคุณต้องการเปรียบเทียบจำนวนจุดลอยตัวสองสามตัวเลือกที่น่าสนใจอาจเป็นbc:

define x(a, b) {
    if (a > b) {
       return (a);
    }
    return (b);
 }

จะเทียบเท่าtest $1 -gt $2และใช้ในเปลือก:

max () { printf '
    define x(a, b) {
        if (a > b) {
           return (a);
        }
        return (b);
     }
     x(%s, %s)
    ' $1 $2 | bc -l
}

ยังเร็วกว่าเกือบ 2.5 เท่าprintf | sort | head(สำหรับตัวเลขสองตัว)

หากคุณสามารถพึ่งพาส่วนขยาย GNU ได้คุณสามารถbcใช้read()ฟังก์ชั่นเพื่ออ่านตัวเลขลงในbcsript ได้โดยตรง


ความคิดของฉันอย่างแน่นอน - ฉันเพิ่งจะรีดออก แต่คุณเอาชนะฉันไปที่: dc -e "${max}sm[z0=?dlm<Mps0lTx]ST[?z0!=Tq]S?[s0lm]SMlTx"- โอ้ยกเว้นว่าdcจะทำสิ่งทั้งหมด(ยกเว้นก้องแม้ว่ามันจะทำได้) - มันอ่าน stdin และพิมพ์อย่างใดอย่างหนึ่ง$maxหรือหมายเลขอินพุตขึ้นอยู่กับว่า มีขนาดเล็กลง อย่างไรก็ตามฉันไม่สนใจที่จะอธิบายและคำตอบของคุณดีกว่าที่ฉันจะเขียน ได้โปรดอัปเดตของฉันด้วย
mikeserv

@mikeserv จริง ๆ แล้วมีdcสคริปต์อธิบายจะดีจริง ๆ RPN ไม่เห็นบ่อยครั้งวันนี้
เตอร์

ย้อนกลับสัญกรณ์โปแลนด์ บวกถ้าdcสามารถทำ I / O ด้วยตัวเองมันจะยิ่งสวยงามกว่า
เตอร์

4

ในการรับมูลค่าที่มากกว่า $ a และ $ b ให้ใช้สิ่งนี้:

[ "$a" -gt "$b" ] && $a || $b

แต่คุณต้องการบางสิ่งบางอย่างที่คุณอาจไม่ได้หมายถึงการดำเนินการจำนวนดังนั้นเพื่อแสดงมูลค่าที่มากขึ้นของทั้งสองใช้ "echo"

[ "$a" -gt "$b" ] && echo $a || echo $b

ข้างต้นเหมาะอย่างยิ่งในฟังก์ชั่นเปลือกเช่น

max() {
   [ "$1" -gt "$2" ] && echo $1 || echo $2
}

หากต้องการกำหนดตัวแปรที่มากกว่าให้กับตัวแปรทั้งสองให้ใช้เวอร์ชันที่แก้ไขนี้:

[ "$a" -gt "$b" ] && biggest=$a || biggest=$b

หรือใช้ฟังก์ชั่นที่กำหนด:

biggest=$( max $a $b )

รูปแบบฟังก์ชั่นนี้ยังช่วยให้คุณมีโอกาสเพิ่มการตรวจสอบข้อผิดพลาดของอินพุตได้อย่างเป็นระเบียบ

ในการคืนค่าจำนวนทศนิยม / ทศนิยมสูงสุดสองคุณสามารถใช้ awk

decimalmax() { 
   echo $1 $2 | awk '{if ($1 > $2) {print $1} else {print $2}}'; 
}

แก้ไข: การใช้เทคนิคนี้คุณสามารถสร้างฟังก์ชั่น "จำกัด " ซึ่งดำเนินการในทางอื่น ๆ ตามการแก้ไข / บันทึกย่อของคุณ ฟังก์ชั่นนี้จะคืนค่าส่วนล่างของทั้งสองเช่น:

limit() {
   [ "$1" -gt "$2" ] && echo $2 || echo $1
}

ฉันชอบที่จะใส่ฟังก์ชั่นยูทิลิตี้ลงในไฟล์แยกกันเรียกมันmyprogram.funcsและใช้มันในสคริปต์ดังนี้

#!/bin/bash

# Initialization. Read in the utility functions
. ./myprogram.funcs

# Do stuff here
#
[ -z "$1" ] && { echo "Needs a limit as first argument." >&2; exit 1; }

read number
echo $( limit $1 $number )

FWIW สิ่งนี้ยังคงทำในสิ่งที่คุณทำและเวอร์ชั่นของคุณแม้ว่าจะละเอียดมากขึ้นก็มีประสิทธิภาพ

รูปแบบที่กะทัดรัดมากขึ้นนั้นไม่ได้ดีกว่านี้มากนัก แต่ป้องกันความยุ่งเหยิงในสคริปต์ของคุณ หากคุณมีโครงสร้าง if-then-else-fi ง่ายสคริปต์จะขยายออกอย่างรวดเร็ว

หากคุณต้องการใช้การตรวจสอบซ้ำสำหรับหมายเลขที่ใหญ่กว่า / เล็กกว่าหลาย ๆ ครั้งในสคริปต์เดียวให้วางไว้ในฟังก์ชัน รูปแบบฟังก์ชั่นช่วยให้การดีบักและนำกลับมาใช้ใหม่ง่ายขึ้นและช่วยให้คุณสามารถแทนที่ส่วนนั้นของสคริปต์ได้อย่างง่ายดายเช่นด้วยคำสั่ง awk เพื่อให้สามารถจัดการกับเลขทศนิยมที่ไม่ใช่จำนวนเต็ม

หากเป็นกรณีการใช้งานเพียงครั้งเดียวเพียงแค่รหัสในบรรทัด


4

คุณสามารถกำหนดฟังก์ชั่นเป็น

maxnum(){
    if [ $2 -gt $1 ]
    then
        echo $2
    else
        echo $1
    fi
}

เรียกว่าเป็นและมันสะท้อนmaxnum 54 42 54คุณสามารถเพิ่มข้อมูลการตรวจสอบภายในฟังก์ชั่น (เช่นสองข้อโต้แย้งหรือตัวเลขเป็นข้อโต้แย้ง) หากคุณต้องการ


กระสุนส่วนใหญ่ไม่ได้ทำเลขคณิตทศนิยม แต่มันใช้งานได้สำหรับจำนวนเต็ม
orion

1
ฟังก์ชันนี้ไม่รองรับ POSIX โดยไม่จำเป็น เปลี่ยนfunction maxnum {เป็นmaxnum() {และมันจะทำงานกับกระสุนได้มากขึ้น
ชาร์ลส์ดัฟฟี่

2

จากเชลล์สคริปต์มีวิธีการใช้วิธีการคงที่สาธารณะ Java ใด ๆ (และเช่นMath.min () ) จาก bash บน Linux:

. jsbInit
jsbStart 
A=2 
B=3 
C=$(jsb Math.min "$A" "$B")
echo "$C"

ต้องใช้Java Shell Bridge https://sourceforge.net/projects/jsbridge/

อย่างรวดเร็วเพราะวิธีการที่สายจะภายในประปา ; ไม่ต้องดำเนินการ


0

คนส่วนใหญ่จะทำsort -n input | head -n1(หรือหาง) มันดีพอสำหรับสถานการณ์การเขียนสคริปต์ส่วนใหญ่ อย่างไรก็ตามนี่มันค่อนข้างงุ่มง่ามถ้าคุณมีตัวเลขในบรรทัดแทนที่จะเป็นคอลัมน์ - คุณต้องพิมพ์ออกมาในรูปแบบที่เหมาะสม ( tr ' ' '\n'หรืออะไรทำนองนั้น)

เชลล์ไม่เหมาะอย่างยิ่งสำหรับการประมวลผลเชิงตัวเลข แต่คุณสามารถเพียงแค่ไพพ์เข้าไปในโปรแกรมอื่นที่ดีกว่า ขึ้นอยู่กับความชอบของคุณเองคุณโทรสูงสุดdc(บิต obfuscated แต่ถ้าคุณรู้ว่าสิ่งที่คุณทำมันได้ดี - ดูคำตอบของ mikeserv) awk 'NR==1{max=$1} {if($1>max){max=$1}} END { print max }'หรือ หรืออาจจะเป็นperlหรือpythonถ้าคุณต้องการ ทางออกหนึ่ง (ถ้าคุณเต็มใจที่จะติดตั้งและใช้ซอฟต์แวร์ที่รู้จักน้อยกว่า) จะเป็นised(โดยเฉพาะถ้าข้อมูลของคุณอยู่ในบรรทัดเดียว: คุณเพียงแค่ต้องทำised --l input.dat 'max$1')


เนื่องจากคุณขอตัวเลขสองตัวนี่เป็นจำนวนที่มากเกินไป ควรจะเพียงพอ:

python -c "print(max($j,$k))"

1
อาจจะดีกว่าถ้าคุณใช้sys.argv:python2 -c 'import sys; print (max(sys.argv))' "$@"
muru

1
ข้อโต้แย้งที่sort + headมากเกินไป แต่pythonไม่ได้คำนวณ
mikeserv

วิธีการทั้งหมดด้านบนบรรทัดได้รับการออกแบบมาเพื่อจัดการกับชุดตัวเลขจำนวนมากและแนะนำการใช้งานประเภทนี้อย่างชัดเจน (อ่านจากไพพ์หรือไฟล์) ต่ำสุด / สูงสุดสำหรับ 2 ข้อโต้แย้งเป็นคำถามที่ให้ความรู้สึกที่แตกต่าง - มันเรียกใช้ฟังก์ชันแทนสตรีม ฉันแค่หมายถึงว่าวิธีการสตรีมนั้นเกินความจริง - เครื่องมือที่คุณใช้นั้นไม่มีกฎเกณฑ์ฉันใช้pythonเพราะมันเรียบร้อย
orion

ฉันจะเรียกนี้ neater วิธีการแก้ปัญหาแต่ที่อาจจะเป็นเพราะผมเป็นpythonคนหัวดื้อ(หรือเพราะมันไม่จำเป็นต้องใช้ส้อมและล่ามยักษ์เพิ่มเติม) หรืออาจจะทั้งคู่
mikeserv

@mikeserv ฉันก็จะใช้มันเหมือนกันถ้าฉันรู้ว่ามันเป็นจำนวนเต็ม วิธีแก้ปัญหาทั้งหมดที่ฉันกล่าวถึงอยู่ภายใต้การสันนิษฐานว่าตัวเลขอาจลอย - ทุบตีไม่ได้ทำจุดลอยตัวและถ้า zsh เป็นเปลือกหอยพื้นเมืองของคุณคุณจะต้องแยก (และอาจมีด)
orion
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.