อ่านตัวแปรใน bash ด้วยค่าเริ่มต้น


191

ฉันต้องการอ่านค่าจากเทอร์มินัลในสคริปต์ทุบตี ฉันต้องการให้ค่าเริ่มต้นที่ผู้ใช้สามารถเปลี่ยนแปลงได้

# Please enter your name: Ricardo^

ในสคริปต์นี้พรอมต์คือ "โปรดป้อนชื่อของคุณ:" ค่าเริ่มต้นคือ "Ricardo" และเคอร์เซอร์จะอยู่หลังค่าเริ่มต้น มีวิธีการทำเช่นนี้ในสคริปต์ทุบตี?

คำตอบ:


280

คุณสามารถใช้การขยายพารามิเตอร์เช่น

read -p "Enter your name [Richard]: " name
name=${name:-Richard}
echo $name

การรวมค่าเริ่มต้นในพรอมต์ระหว่างวงเล็บเหลี่ยมเป็นระเบียบปฏิบัติที่ค่อนข้างทั่วไป


7
ในที่สุดฉันก็ลงมือทำบางสิ่งตามนี้ อ่านหนังสือลงในตัวแปรชั่วคราวแล้วใช้input name=${input:-$name}
Ricardo Marimon

41
นี่ไม่ได้ตอบคำถามจริงๆ ควรแสดงค่าเริ่มต้นในพร้อมท์
Dr. Person Person II II

3
และจะname=${!input:-$name}ทำอย่างไร
Harry Lee

8
@ Dr.PersonPersonII - คุณสามารถเพิ่มค่าเริ่มต้นโดยทำสิ่งนี้: read -p "ป้อนชื่อโฮสต์ระยะไกล [$ remote_host_default]:" remote_host remote_host = $ {remote_host: - $ remote_host_default}
Dobler

4
$1จะกลายเป็น${1:-some_default_string}
ThorSummoner

160
read -e -p "Enter Your Name:" -i "Ricardo" NAME

echo $NAME

1
คำตอบที่ดี! ฉันแค่อยากจะพูดถึงว่าฉันมีปัญหากับมันเพราะฉันไม่เห็นช่องว่างระหว่าง "ริคาร์โด้" และชื่อ แต่เมื่อฉันคิดออกว่า .... มายากล ! ขอบคุณ!
Mr Mikkél

40
น่าเสียดายที่ -i ไม่ใช่ตัวเลือกที่ถูกต้องสำหรับ OSX 10.7
undefined

3
@BrianMortenson คุณสามารถอัปเกรด bash โดยใช้ homebrew: stackoverflow.com/questions/16416195/…
antonagestam

2
คำตอบนี้แสดงวิธีการทำงานบน OS X (Bash 3.x) นี้: stackoverflow.com/questions/22634065/…
Christoph Petschnig

3
เพียงแค่ทราบว่า-eน่าจะเป็นข้อบังคับเพื่ออนุญาตให้-iใช้งานได้จริง
MestreLion

48

ใน Bash 4:

name="Ricardo"
read -e -i "$name" -p "Please enter your name: " input
name="${input:-$name}"

นี่แสดงชื่อหลังจากพรอมต์เช่นนี้

Please enter your name: Ricardo

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


ไม่สามารถใช้ bash4 ได้เนื่องจากไม่ได้มาตรฐานในการแจกแจงแบบเดเบียน ฉันต้องการสิ่งที่จะทำงานได้โดยไม่ต้องยุ่งยากอะไรมาก
Ricardo Marimon

1
ไม่จำเป็นต้องใช้บรรทัดสุดท้ายของรหัสเพียงใช้nameแทนinputในreadคำสั่ง
RNA

1
@RNAer: โดยใช้ตัวแปรพิเศษค่าของ$nameจะถูกเก็บรักษาไว้หากผู้ใช้ลบค่าที่เสนอ (ดังนั้นจึงใส่สตริง null) ทุกอย่างขึ้นอยู่กับความต้องการของคุณ ฉันพูดมากในคำตอบของฉัน คุณกำลังขวา nameแต่ที่ฉันจะได้รับอย่างชัดเจนมากขึ้นและกล่าวว่าหากตรวจสอบสายไม่ได้ใช้แล้วตัวแปรที่จะได้รับ
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

1
@DennisWilliamson: คุณพูดถูก เป็นการปฏิบัติที่ดีถ้านั่นคือสิ่งที่เราต้องการ
RNA

16

รหัส:

IN_PATH_DEFAULT="/tmp/input.txt"
read -p "Please enter IN_PATH [$IN_PATH_DEFAULT]: " IN_PATH
IN_PATH="${IN_PATH:-$IN_PATH_DEFAULT}"

OUT_PATH_DEFAULT="/tmp/output.txt"
read -p "Please enter OUT_PATH [$OUT_PATH_DEFAULT]: " OUT_PATH
OUT_PATH="${OUT_PATH:-$OUT_PATH_DEFAULT}"

echo "Input: $IN_PATH Output: $OUT_PATH"

วิ่งตัวอย่าง:

Please enter IN_PATH [/tmp/input.txt]: 
Please enter OUT_PATH [/tmp/output.txt]: ~/out.txt
Input: /tmp/input.txt Output: ~/out.txt

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

16

ฉันพบคำถามนี้โดยมองหาวิธีที่จะนำเสนอสิ่งที่ชอบ:

Something interesting happened.  Proceed [Y/n/q]:

ใช้ตัวอย่างข้างต้นฉันอนุมานนี้: -

echo -n "Something interesting happened.  "
DEFAULT="y"
read -e -p "Proceed [Y/n/q]:" PROCEED
# adopt the default, if 'enter' given
PROCEED="${PROCEED:-${DEFAULT}}"
# change to lower case to simplify following if
PROCEED="${PROCEED,,}"
# condition for specific letter
if [ "${PROCEED}" == "q" ] ; then
  echo "Quitting"
  exit
# condition for non specific letter (ie anything other than q/y)
# if you want to have the active 'y' code in the last section
elif [ "${PROCEED}" != "y" ] ; then
  echo "Not Proceeding"
else
  echo "Proceeding"
  # do proceeding code in here
fi

หวังว่าจะช่วยให้ใครบางคนไม่ต้องคิดตรรกะถ้าพวกเขาพบปัญหาเดียวกัน


ดีมาก. อาจมีการปรับปรุงให้ดีขึ้นเล็กน้อยเพื่อทำซ้ำคำถามหากมีคนเพียงป้อน "k" หรืออย่างอื่นนอกเหนือจากตัวเลือกที่กำหนด
erikbwork

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


6
name=Ricardo
echo "Please enter your name: $name \c"
read newname
[ -n "$newname" ] && name=$newname

ตั้งค่าเริ่มต้น; พิมพ์; อ่านค่าใหม่ หากมีค่าใหม่ให้ใช้แทนค่าเริ่มต้น มี (หรือเคย) รูปแบบบางอย่างระหว่างเชลล์และระบบเกี่ยวกับวิธีการปราบปรามการขึ้นบรรทัดใหม่เมื่อสิ้นสุดพรอมต์ สัญกรณ์ '\ c' ดูเหมือนว่าจะทำงานบน MacOS X 10.6.3 พร้อมกับทุบตี 3.x และทำงานกับ Unix ส่วนใหญ่ที่มาจาก System V โดยใช้ Bourne หรือ Korn shell

นอกจากนี้โปรดทราบว่าผู้ใช้อาจไม่ทราบว่าเกิดอะไรขึ้นเบื้องหลัง; ข้อมูลใหม่ของพวกเขาจะถูกป้อนหลังจากชื่อบนหน้าจอ การจัดรูปแบบอาจดีกว่า:

echo "Please enter your name ($name): \c"

printfสามารถพกพาได้มากกว่าecho
ghostdog74

3
@ ghostdog74: อาจจะเป็นอย่างนั้น พวกเราที่เรียนรู้การเขียนโปรแกรมเชลล์เมื่อ 25 ปีที่แล้วมีช่วงเวลาที่ยากลำบากในการปฏิบัติซึ่งการปฏิบัติของเรายังคงมีความเกี่ยวข้อง ดูเหมือนว่า bash จะเขียนขึ้นใหม่ทุกอย่าง ฉันรู้ว่า printf ใช้เวลานานในการควบคุม - ฉันไม่ค่อยได้ใช้มันสักเท่าไหร่ (อาจจะ - ไม่เคย?) ฉันได้รับความประทับใจฉันควรปิดเชลล์จนกว่าฉันจะได้เรียนรู้การทุบตี ตลกดี ซอฟต์แวร์ที่ฉันใช้งานมีเชลล์สคริปต์ที่ทำงานได้ไม่ดี แต่ปัญหาไม่ได้เป็น bash-isms ฉันเพิ่งเบื่อกับการแก้ไข ' if (test -z "$xxx"); ...' และ C เชลล์อื่น ๆ
Jonathan Leffler

ฉันประหลาดใจที่ bash รองรับ\cเนื่องจากมันรองรับecho -n! อย่างไรก็ตามคุณต้องเพิ่ม-eเพื่อให้ได้เสียงสะท้อนของ bash เพื่อตีความทางหนี ฉันเดาว่า\cเป็นสิ่งที่ยังไม่ได้ชำระ:echo -e "Syntax slightly off\c, but I've learned so much from what you've shared. Thanks, @JonathanLeffler!"
jpaugh

1
#Script for calculating various values in MB
echo "Please enter some input: "
read input_variable
echo $input_variable | awk '{ foo = $1 / 1024 / 1024 ; print foo "MB" }'

3
โปรดเพิ่มคำอธิบายให้กับคำตอบของคุณ
Sufiyan Ghori

-1

พารามิเตอร์ -e และ -t ไม่ทำงานร่วมกัน ฉันลองใช้นิพจน์และผลลัพธ์คือตัวอย่างโค้ดต่อไปนี้:

QMESSAGE="SHOULD I DO YES OR NO"
YMESSAGE="I DO"
NMESSAGE="I DO NOT"
FMESSAGE="PLEASE ENTER Y or N"
COUNTDOWN=2
DEFAULTVALUE=n
#----------------------------------------------------------------#
function REQUEST ()
{
read -n1 -t$COUNTDOWN -p "$QMESSAGE ? Y/N " INPUT
    INPUT=${INPUT:-$DEFAULTVALUE}
    if  [ "$INPUT" = "y" -o "$INPUT" = "Y" ] ;then
        echo -e "\n$YMESSAGE\n"
        #COMMANDEXECUTION
    elif    [ "$INPUT" = "n" -o "$INPUT" = "N" ] ;then
        echo -e "\n$NMESSAGE\n"
        #COMMANDEXECUTION
    else
        echo -e "\n$FMESSAGE\n"
    REQUEST
    fi
}
REQUEST

คำตอบของคุณไม่เกี่ยวกับคำถามใช่หรือไม่…
gniourf_gniourf

มันหลีกเลี่ยงการใช้พารามิเตอร์ -e และ -t codeline นี้ (-e และ -i สำหรับค่าเริ่มต้น): read -e -p "ป้อนชื่อของคุณ:" -i "Ricardo" NAME ไม่สามารถใช้งานกับ countdowntimer (-t)
speefak

ใช่ แต่นั่นไม่ได้ถามในคำถามใช่มั้ย
gniourf_gniourf

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