วิธีรับอินพุตกล่องโต้ตอบที่นำไปสู่ตัวแปรได้อย่างไร


18

ฉันสอนตัวเองด้วยการทุบตีสคริปต์และพบปัญหา ฉันเขียนสคริปต์เพื่อรับอินพุตจากผู้ใช้โดยใช้คำสั่ง 'read' และทำให้อินพุตนั้นเป็นตัวแปรที่จะใช้ในภายหลังในสคริปต์ สคริปต์ทำงานได้ แต่ ....

ฉันต้องการติดตั้งโดยใช้ 'โต้ตอบ' ฉันพบว่า

'dialog --inboxbox' จะนำเอาต์พุตไปยัง 'stderr' และเพื่อให้ได้อินพุตนั้นเป็นตัวแปรคุณต้องนำไปยังไฟล์แล้วดึงข้อมูลนั้นมา รหัสที่ฉันพบเพื่ออธิบายสิ่งนี้คือ:

#!/bin/bash
dialog --inputbox \

"What is your username?" 0 0 2> /tmp/inputbox.tmp.$$

retval=$?

input=`cat /tmp/inputbox.tmp.$$`

rm -f /tmp/inputbox.tmp.$$

case $retval in
0)

echo "Your username is '$input'";;
1)

echo "Cancel pressed.";;

esac

ฉันเห็นว่ามันกำลังส่ง sdterr ไปยัง /tmp/inputbox.tmp.$$ ด้วย 2> แต่ไฟล์เอาต์พุตดูเหมือนว่า 'inputbox.tmp.21661' เมื่อฉันพยายาม cat ไฟล์มันทำให้ฉันมีข้อผิดพลาด ดังนั้นฉันยังคงไม่สามารถรับอินพุตของผู้ใช้จาก - อินพุตกล่องเป็นตัวแปร

ตัวอย่างสคริปต์:

echo "  What app would you like to remove? "

read dead_app

sudo apt-get remove --purge $dead_app

ดังนั้นอย่างที่คุณเห็นมันเป็นสคริปต์พื้นฐาน เป็นไปได้ไหมที่จะรับตัวแปรเป็นคำจากdialog --inputbox?


จากประสบการณ์ของฉันสคริปต์ทำงานได้ดีถ้าคุณลบบรรทัดว่างหลังจากบรรทัดที่ 2 หรือคุณสามารถใช้mktempคำสั่งเพื่อสร้างไฟล์ชั่วคราว
jarno

คำตอบ:


16

: DI อธิบายไม่ได้ !!! หากคุณสามารถเข้าใจสิ่งที่พวกเขากำลังพูดถึงในคู่มือการใช้สคริปต์การทุบตีขั้นสูง: บทที่ 20 การเปลี่ยนเส้นทาง I / Oให้เขียนคำตอบใหม่และฉันจะให้50rep :

exec 3>&1;
result=$(dialog --inputbox test 0 0 2>&1 1>&3);
exitcode=$?;
exec 3>&-;
echo $result $exitcode;

การอ้างอิง: ไดอะล็อกใน bash ไม่ได้รับตัวแปรอย่างถูกต้อง

^ answer จาก@Sneetsher (4 ก.ค. 2014)

ตามที่ร้องขอฉันจะพยายามอธิบายสิ่งที่ตัวอย่างนี้ทำทีละบรรทัด

โปรดทราบว่าฉันจะทำให้มันง่ายขึ้นโดยการเว้น;เครื่องหมายอัฒภาคทั้งหมดที่บรรทัดสิ้นสุดเพราะไม่จำเป็นถ้าเราเขียนหนึ่งคำสั่งต่อบรรทัด

I / O - สตรีม:

ก่อนอื่นคุณต้องเข้าใจกระแสการสื่อสาร มี 10 สตรีมซึ่งมีหมายเลขตั้งแต่ 0 ถึง 9:

  • สตรีม 0 ("STDIN"):
    "อินพุตมาตรฐาน" ซึ่งเป็นสตรีมเริ่มต้นที่ใช้ในการอ่านข้อมูลจากแป้นพิมพ์

  • สตรีม 1 ("STDOUT"):
    "เอาต์พุตมาตรฐาน" ซึ่งเป็นสตรีมเอาต์พุตเริ่มต้นที่ใช้แสดงข้อความปกติในเทอร์มินัล

  • สตรีม 2 ("STDERR"): "ข้อผิดพลาดมาตรฐาน" ซึ่งเป็นสตรีมเอาต์พุตเริ่มต้นที่ใช้เพื่อแสดงข้อผิดพลาดหรือข้อความอื่น ๆ เพื่อจุดประสงค์พิเศษในเทอร์มินัล

  • ลำธาร 3-9:
    เพิ่มเติมลำธารที่สามารถใช้งานได้อย่างอิสระ โดยค่าเริ่มต้นจะไม่ถูกใช้และไม่มีอยู่จนกว่าจะมีบางอย่างพยายามใช้

โปรดทราบว่า "สตรีม" ทั้งหมดจะถูกแทนด้วยตัวอธิบายไฟล์ใน/dev/fd(ซึ่งเป็นลิงก์สัญลักษณ์/proc/self/fdซึ่งมีลิงก์สัญลักษณ์อื่นสำหรับสตรีมทุกครั้ง ... มันค่อนข้างซับซ้อนและไม่สำคัญกับพฤติกรรมของพวกเขาดังนั้นฉันจึงหยุดที่นี่) ลำธารมาตรฐานยังมี/dev/stdin, /dev/stdoutและ/dev/stderr(ซึ่งมีการเชื่อมโยงสัญลักษณ์อีกครั้ง ฯลฯ ... )

บท:

  • exec 3>&1

    Bash ในตัวexecสามารถใช้เพื่อเปลี่ยนเส้นทางการสตรีมไปยังเชลล์ซึ่งหมายความว่ามันมีผลกับคำสั่งต่อไปนี้ทั้งหมด สำหรับข้อมูลเพิ่มเติมเรียกใช้help execใน terminal ของคุณ

    ในกรณีพิเศษนี้สตรีม 3 จะถูกเปลี่ยนเส้นทางไปยังสตรีม 1 (STDOUT) ซึ่งหมายความว่าทุกสิ่งที่เราส่งไปยังสตรีม 3 ในภายหลังจะปรากฏในเทอร์มินัลของเราราวกับว่าปกติจะพิมพ์ไปยัง STDOUT

  • result=$(dialog --inputbox test 0 0 2>&1 1>&3)

    บรรทัดนี้ประกอบด้วยหลายส่วนและโครงสร้างการสร้างประโยค:

    • result=$(...)
      โครงสร้างนี้รันคำสั่งในวงเล็บและกำหนดเอาท์พุท (STDOUT) resultเพื่อตัวแปรทุบตี $resultมันผ่านการอ่าน ทั้งหมดนี้จะอธิบายอย่างใดใน man bashlooong

    • dialog --inputbox TEXT HEIGHT WIDTH
      คำสั่งนี้แสดงกล่อง TUI ที่มี TEXT ที่กำหนดฟิลด์ป้อนข้อความและปุ่มสองปุ่มตกลงและยกเลิก หากได้รับการเลือก OK คำสั่งจะออกจากสถานะ 0 และพิมพ์ข้อความที่ป้อนไปยัง STDERR หากได้รับการเลือก CANCEL คำสั่งนั้นจะออกจากรหัส 1 และไม่พิมพ์อะไรเลย man dialogสำหรับข้อมูลเพิ่มเติมโปรดอ่าน

    • 2>&1 1>&3
      คำสั่งการเปลี่ยนเส้นทางสองคำสั่งเหล่านี้ พวกเขาจะถูกตีความจากขวาไปซ้าย:

      1>&3 เปลี่ยนเส้นทางสตรีมของคำสั่ง 1 (STDOUT) ไปยังสตรีมที่กำหนดเอง 3

      2>&1 เปลี่ยนเส้นทางหลังจากนั้นสตรีมของคำสั่ง 2 (STDERR) เพื่อสตรีม 1 (STDOUT)

      นั่นหมายความว่าทุกอย่างที่คำสั่งพิมพ์ไปยัง STDOUT จะปรากฏในสตรีม 3 ในขณะที่ทุกสิ่งที่ตั้งใจจะแสดงบน STDERR ตอนนี้จะถูกเปลี่ยนเส้นทางไปยัง STDOUT

    ดังนั้นทั้งบรรทัดแสดงข้อความแจ้งเตือน (บน STDOUT ซึ่งเปลี่ยนเส้นทางไปที่สตรีม 3 ซึ่งเชลล์เปลี่ยนเส้นทางอีกครั้งกลับไปที่ STDOUT ในท้ายที่สุด - ดูexec 3>&1คำสั่ง) และกำหนดข้อมูลที่ป้อน (ส่งกลับผ่าน STDERR แล้วเปลี่ยนเส้นทางไปยัง STDOUT) resultตัวแปรทุบตี

  • exitcode=$?

    รหัสนี้ดึงรหัสออกคำสั่งดำเนินการก่อนหน้านี้ของ (จากที่นี่dialog) ผ่านลิขสิทธิ์ทุบตีตัวแปร$?(เสมอถือรหัสทางออกที่ผ่านมา) exitcodeและก็เก็บไว้ในตัวแปรทุบตีของเราเอง มันสามารถอ่านได้$exitcodeอีกครั้ง คุณสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ในman bashแต่อาจใช้เวลาสักครู่ ...

  • exec 3>&-

    Bash ในตัวexecสามารถใช้เพื่อเปลี่ยนเส้นทางการสตรีมไปยังเชลล์ซึ่งหมายความว่ามันมีผลกับคำสั่งต่อไปนี้ทั้งหมด สำหรับข้อมูลเพิ่มเติมเรียกใช้help execใน terminal ของคุณ

    ในกรณีพิเศษนี้สตรีม 3 จะถูกเปลี่ยนเส้นทางไปที่ "สตรีม -" ซึ่งหมายความว่าควรปิด ข้อมูลที่ส่งไปยังสตรีม 3 จะไม่ถูกเปลี่ยนเส้นทางจากทุกที่ต่อจากนี้ไป

  • echo $result $exitcode

    echoคำสั่งง่ายๆนี้(ข้อมูลเพิ่มเติมเกี่ยวกับman echo) เพียงพิมพ์เนื้อหาของตัวแปร Bash สองตัวresultและexitcodeไปยัง STDOUT เนื่องจากเราไม่มีการเปลี่ยนเส้นทางสตรีมอย่างชัดเจนหรือโดยปริยายที่นี่อีกต่อไปพวกเขาจะปรากฏบน STDOUT จริงๆและดังนั้นจึงแสดงในเทอร์มินัล ช่างน่าอัศจรรย์จริงๆ! ;-)

สรุป:

อันดับแรกเราตั้งค่าเชลล์เพื่อเปลี่ยนเส้นทางทุกสิ่งที่เราส่งไปยังสตรีมแบบกำหนดเอง 3 กลับไปที่ STDOUT เพื่อให้ปรากฏในเทอร์มินัลของเรา

จากนั้นเราเรียกใช้dialogคำสั่งเปลี่ยนเส้นทาง STDOUT ดั้งเดิมไปยังสตรีมแบบกำหนดเอง 3 ของเราเนื่องจากต้องการแสดงในตอนท้าย แต่เราต้องใช้สตรีม STDOUT ชั่วคราวเพื่อสิ่งอื่น
เราเปลี่ยนเส้นทาง STDERR ดั้งเดิมของคำสั่งที่ได้รับคืนข้อมูลผู้ใช้ของหน้าต่างการสนทนาไปยัง STDOUT หลังจากนั้น
ตอนนี้เราสามารถจับภาพ STDOUT (ซึ่งถือเป็นข้อมูลที่มีการเปลี่ยนเส้นทางจาก STDERR) $resultและเก็บไว้ในตัวแปรของเรา มันมีการป้อนข้อมูลของผู้ใช้ที่ต้องการในขณะนี้!

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

หลังจากนั้นเราปิดสตรีม 3 อีกครั้งเนื่องจากเราไม่ต้องการอีกต่อไปเพื่อหยุดการเปลี่ยนเส้นทางเพิ่มเติม

ในที่สุดเรามักจะส่งออกเนื้อหาของตัวแปรทั้งสอง$result(อินพุตผู้ใช้ของหน้าต่างการสนทนา) และ$exitcode(0 สำหรับตกลง, 1 สำหรับยกเลิก) ไปยังเทอร์มินัล


ฉันคิดว่าการใช้execมีความซับซ้อนเกินความจำเป็น ทำไมไม่เพียงแค่เรา--stdoutเลือกdialogหรือเปลี่ยนเส้นทางการส่งออกโดย2>&1 >/dev/tty?
jarno

โปรดดูของฉันคำตอบ
jarno

3
คำตอบที่ดี! อย่างไรก็ตามฉันเชื่อว่าคุณมีบันทึกย่อหนึ่งที่ไม่ถูกต้อง - คุณบอกว่า "พวกเขาจะถูกตีความจากขวาไปซ้าย" แต่ฉันเชื่อว่าไม่เป็นความจริง จากคู่มือทุบตีgnu.org/software/bash/manual/html_node/Redirections.htmlเป็นการระบุว่าการเปลี่ยนเส้นทางเกิดขึ้นเมื่อพบ (เช่นซ้ายไปขวา)
ralfthewise

14

การใช้เครื่องมือของไดอะล็อก: --output-fd flag

หากคุณอ่าน man page สำหรับไดอะล็อกจะมีตัวเลือก--output-fdที่ให้คุณตั้งค่าอย่างชัดเจนว่าเอาต์พุตไปที่ใด (STDOUT 1, STDERR 2) แทนที่จะเป็นค่าเริ่มต้นไปที่ STDERR

ร้องคุณสามารถเห็นฉันใช้dialogคำสั่งตัวอย่างด้วยการระบุว่าการส่งออกอย่างชัดเจนจะต้องไปที่ file descriptor 1 ซึ่งช่วยให้ฉันบันทึกไว้ใน MYVAR

MYVAR=$(dialog --inputbox "THIS OUTPUT GOES TO FD 1" 25 25 --output-fd 1)

ป้อนคำอธิบายรูปภาพที่นี่

ใช้ชื่อ pipes

วิธีทางเลือกซึ่งมีจำนวนมากที่มีศักยภาพที่ซ่อนอยู่คือการใช้สิ่งที่เรียกไปป์ที่มีชื่อ

#!/bin/bash

mkfifo /tmp/namedPipe1 # this creates named pipe, aka fifo

# to make sure the shell doesn't hang, we run redirection 
# in background, because fifo waits for output to come out    
dialog --inputbox "This is an input box  with named pipe" 40 40 2> /tmp/namedPipe1 & 

# release contents of pipe
OUTPUT="$( cat /tmp/namedPipe1  )" 


echo  "This is the output " $OUTPUT
# clean up
rm /tmp/namedPipe1 

ป้อนคำอธิบายรูปภาพที่นี่

ภาพรวมเชิงลึกเพิ่มเติมของคำตอบของ user.dzด้วยวิธีอื่น

คำตอบดั้งเดิมโดย user.dz และคำอธิบายของ ByteCommanderว่าทั้งสองเป็นโซลูชันที่ดีและภาพรวมของสิ่งที่ทำ อย่างไรก็ตามฉันเชื่อว่าการวิเคราะห์เชิงลึกอาจเป็นประโยชน์ในการอธิบายว่าทำไมจึงใช้งานได้

ก่อนอื่นสิ่งสำคัญคือต้องเข้าใจสองสิ่ง: ปัญหาที่เราพยายามแก้ไขคืออะไรและการทำงานพื้นฐานของกลไกเชลล์ที่เราจัดการอยู่คืออะไร ภารกิจคือการดักจับเอาต์พุตของคำสั่งผ่านการทดแทนคำสั่ง ภายใต้ภาพรวมแบบง่าย ๆ ที่ทุกคนรู้การแทนที่คำสั่งจะดักจับstdoutคำสั่งและปล่อยให้มันถูกนำกลับมาใช้โดยอย่างอื่น ในกรณีนี้result=$(...)เป็นส่วนหนึ่งควรบันทึกผลลัพธ์ของสิ่งที่คำสั่งที่กำหนดโดยเข้าไปในตัวแปรที่เรียกว่า...result

ภายใต้ประทุนแล้วการแทนที่คำสั่งจะถูกนำไปใช้จริงเป็นไพพ์ซึ่งมีกระบวนการลูก (คำสั่งจริงที่รัน) และกระบวนการอ่าน (ซึ่งจะบันทึกเอาต์พุตไปยังตัวแปร) เรื่องนี้เห็นได้ชัดว่ามีร่องรอยของการเรียกระบบ ขอให้สังเกตว่า file descriptor 3 เป็นจุดอ่านจบของไพพ์ในขณะที่ 4 คือปลายเขียน สำหรับกระบวนการ child ของechoซึ่งเขียนไปยังstdout- file descriptor 1, descriptor ไฟล์นั้นจริง ๆ แล้ว copy ของ file descriptor 4, ซึ่งเป็นการเขียนสิ้นสุดของไพพ์ ขอให้สังเกตstderrว่าไม่ได้มีบทบาทในที่นี้เพียงเพราะเป็นท่อเชื่อมต่อstdoutเท่านั้น

$ strace -f -e pipe,dup2,write,read bash -c 'v=$(echo "X")'
...
pipe([3, 4])                            = 0
strace: Process 6200 attached
[pid  6199] read(3,  <unfinished ...>
[pid  6200] dup2(4, 1)                  = 1
[pid  6200] write(1, "X\n", 2 <unfinished ...>
[pid  6199] <... read resumed> "X\n", 128) = 2
[pid  6200] <... write resumed> )       = 2
[pid  6199] read(3, "", 128)            = 0
[pid  6200] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=6200, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

ลองกลับไปที่คำตอบดั้งเดิมสำหรับวินาที ตั้งแต่ตอนนี้เรารู้ว่าการdialogเขียนกล่อง TUI ไปที่stdoutตอบstderrและภายในการแทนที่คำสั่ง stdoutจะถูกไพพ์ไปที่อื่นเรามีส่วนหนึ่งของการแก้ปัญหา - เราจำเป็นต้อง rewire file descriptors ในลักษณะที่stderrจะถูกไพพ์ไปยังกระบวนการอ่าน นี่เป็น2>&1ส่วนหนึ่งของคำตอบ อย่างไรก็ตามเราจะทำอะไรกับกล่อง TUI

นั่นคือสิ่งที่ file descriptor 3 เข้ามาdup2()syscall ช่วยให้เราสามารถทำซ้ำ descriptor ไฟล์ทำให้พวกเขาอ้างถึงสถานที่เดียวกันได้อย่างมีประสิทธิภาพ ตัวอธิบายไฟล์ของกระบวนการที่มีการควบคุมเทอร์มินัลต่ออยู่จริง ๆ แล้วชี้ไปที่อุปกรณ์เทอร์มินัลเฉพาะ สิ่งนี้ชัดเจนถ้าคุณทำ

$ ls -l /proc/self/fd
total 0
lrwx------ 1 user1 user1 64 Aug 20 10:30 0 -> /dev/pts/5
lrwx------ 1 user1 user1 64 Aug 20 10:30 1 -> /dev/pts/5
lrwx------ 1 user1 user1 64 Aug 20 10:30 2 -> /dev/pts/5
lr-x------ 1 user1 user1 64 Aug 20 10:30 3 -> /proc/6424/fd

/dev/pts/5อุปกรณ์เทอร์มินัลหลอกของฉันอยู่ที่ไหน ดังนั้นหากเราสามารถบันทึกปลายทางนี้เรายังสามารถเขียนกล่อง TUI ลงบนหน้าจอเทอร์มินัล นั่นคือสิ่งที่exec 3>&1ทำ เมื่อคุณเรียกคำสั่งที่มีการเปลี่ยนเส้นทางcommand > /dev/nullเชลล์จะส่งผ่านตัวอธิบายไฟล์ stdout จากนั้นใช้dup2()เพื่อเขียนไฟล์ descriptor /dev/nullนั้น execคำสั่งดำเนินการสิ่งที่คล้ายกับdup2()อธิบายไฟล์สำหรับเซสชันเปลือกทั้งหมดจึงทำให้สืบทอดคำสั่งเปลี่ยนเส้นทางแล้วอธิบายไฟล์ exec 3>&1เช่นเดียวกันกับ ตัวอธิบายไฟล์3จะอ้างถึง / ชี้ไปที่เทอร์มินัลการควบคุมและคำสั่งใด ๆ ที่ทำงานในเชลล์เซสชั่นนั้นจะรู้เกี่ยวกับมัน

ดังนั้นเมื่อresult=$(dialog --inputbox test 0 0 2>&1 1>&3);เกิดขึ้นเชลล์จะสร้างไพพ์สำหรับไดอะล็อกเพื่อเขียน แต่ยัง2>&1จะทำให้ไฟล์ descriptor ของคำสั่ง 2 ถูกทำซ้ำไปยัง descriptor ไฟล์เขียนของไพพ์นั้น ในขณะที่ file descriptor 1 จะถูกทำซ้ำไปที่ 3 ซึ่งจะทำให้ file descriptor 1 ยังคงอ้างถึงเทอร์มินัลการควบคุมและกล่องโต้ตอบ TUI จะปรากฏขึ้นบนหน้าจอ

/dev/ttyตอนนี้มีจริงสั้นมือสำหรับสถานีควบคุมปัจจุบันของกระบวนการซึ่งเป็น ดังนั้นวิธีการแก้ปัญหาสามารถลดความซับซ้อนโดยไม่ต้องใช้ตัวอธิบายไฟล์เพียงเข้าไปใน:

result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);
echo "$result"

สิ่งสำคัญที่ควรจำ:

  • file descriptors สืบทอดมาจาก shell โดยแต่ละคำสั่ง
  • การทดแทนคำสั่งถูกนำไปใช้เป็นไพพ์
  • ตัวอธิบายไฟล์ที่ซ้ำกันจะอ้างถึงตำแหน่งเดียวกันกับที่เป็นต้นฉบับ แต่เราสามารถจัดการแต่ละตัวให้คำอธิบายไฟล์แยกจากกัน

ดูสิ่งนี้ด้วย


manpage บอกด้วยว่า--stdoutตัวเลือกนั้นอาจเป็นอันตรายและล้มเหลวได้ง่ายในบางระบบและฉันคิดว่า--output-fd 1ทำเช่นเดียวกัน: --stdout: Direct output to the standard output. This option is provided for compatibility with Xdialog, however using it in portable scripts is not recommended, since curses normally writes its screen updates to the standard output. If you use this option, dialog attempts to reopen the terminal so it can write to the display. Depending on the platform and your environment, that may fail.- อย่างไรก็ตามแนวคิดของ pipe ที่มีชื่อนั้นยอดเยี่ยมมาก!
ผู้บัญชาการ Byte

@ByteCommander "อาจล้มเหลว" ไม่ใช่เรื่องน่าเชื่อมากนักเนื่องจากไม่มีตัวอย่าง นอกจากนี้พวกเขาไม่ได้กล่าวถึงอะไรเกี่ยวกับซึ่งเป็นตัวเลือกที่ผมใช้ที่นี่ไม่ได้--output-fd --stdoutประการที่สองกล่องโต้ตอบจะถูกวาดบน stdout ก่อนเอาท์พุทกลับมาเป็นครั้งที่สอง เราไม่ทำสองสิ่งนี้ในเวลาเดียวกัน อย่างไรก็ตาม --output-fd ไม่ต้องการให้ใช้ fd 1 (STDOUT) โดยเฉพาะ มันสามารถเปลี่ยนเส้นทางไปยังไฟล์อธิบายอื่นได้อย่างง่ายดาย
Sergiy Kolodyazhnyy

ฉันไม่แน่ใจอาจใช้ได้ทุกที่หรือใช้กับระบบส่วนใหญ่เท่านั้น มันใช้งานได้กับฉันและ manpage บอกว่าจะใช้ตัวเลือกที่คล้ายกันด้วยความระมัดระวังคือทั้งหมดที่ฉันรู้แน่นอน แต่อย่างที่ฉันพูดไปแล้ว +1 นั้นสมควรได้รับสำหรับไพพ์ที่มีชื่อแล้ว
ผู้บัญชาการ Byte

ฉันควรแสดงความคิดเห็นที่นี่เพื่อรักษาสมดุล สำหรับฉันนี่อาจเป็นคำตอบที่ได้รับการยอมรับโดยตรงเท่านั้น (1) ใช้เครื่องมือเดียวกันเท่านั้นและใช้ตัวเลือกโดยไม่ต้องใช้เครื่องมือภายนอก (2) ใช้งานได้ใน Ubuntu และทุกสิ่งที่ AU เกี่ยวข้อง : / เศร้า OP ดูเหมือนว่าจะละทิ้งคำถามนี้
user.dz

ข้อดีของการใช้ไปป์ที่มีชื่อแทนที่จะเป็นไฟล์ปกติที่นี่คืออะไร คุณไม่ต้องการที่จะลบท่อหลังการใช้งาน?
jarno

7

: DI อธิบายไม่ได้ !!! หากคุณสามารถเข้าใจสิ่งที่พวกเขากำลังพูดถึงในการอ้างอิง: คู่มือ Bash-Scripting ขั้นสูง: บทที่ 20. การเปลี่ยนเส้นทาง I / O , เขียนคำตอบใหม่และฉันจะให้50rep

ได้รับเงินรางวัลสำหรับคำอธิบายดูคำตอบของ ByteCommander :) นี่เป็นส่วนหนึ่งของประวัติศาสตร์

exec 3>&1;
result=$(dialog --inputbox test 0 0 2>&1 1>&3);
exitcode=$?;
exec 3>&-;
echo $result $exitcode;

แหล่งที่มา: ไดอะล็อกใน bash ไม่ได้คว้าตัวแปรอย่างถูกต้องการ
อ้างอิง: คำแนะนำการใช้สคริปต์การทุบตีขั้นสูง: บทที่ 20 การเปลี่ยนเส้นทาง I / O


ข้อเสนอนั้นยังคงใช้ได้หรือไม่ ฉันคิดว่าฉันสามารถอธิบายสิ่งที่คุณพบเมื่อหนึ่งปีครึ่งที่ผ่านมา ... :-)
Byte Commander

@ ByteCommander แต่อย่างไรก็ตามหากคุณสามารถให้ฉันจะให้คุณว่าฉันจะเป็นคำของฉัน: D
user.dz

@ ByteCommander โปรด ping ฉันหลังจากที่คุณโพสต์
user.dz

1
เสร็จแล้ว! askubuntu.com/a/704616/367990ฉันหวังว่าคุณจะเข้าใจทุกอย่างและเพลิดเพลินกับ "ยูเรก้า!" ขณะ :-D แสดงความคิดเห็นหากมีสิ่งใดที่ไม่ชัดเจน
ผู้บัญชาการไบต์

4

สิ่งนี้ใช้ได้กับฉัน:

#!/bin/bash
input=$(dialog --stdout --inputbox "What is your username?" 0 0)
retval=$?

case $retval in
${DIALOG_OK-0}) echo "Your username is '$input'.";;
${DIALOG_CANCEL-1}) echo "Cancel pressed.";;
${DIALOG_ESC-255}) echo "Esc pressed.";;
${DIALOG_ERROR-255}) echo "Dialog error";;
*) echo "Unknown error $retval"
esac

หน้าคู่มือdialogบอกเกี่ยวกับ --stdout:

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

ใครสามารถบอกได้ว่าแพลตฟอร์มหรือสภาพแวดล้อมใดไม่ทำงาน การเปลี่ยนเส้นทางdialogไปยังผลลัพธ์2>&1 >/dev/ttyแทนที่จะดีขึ้นหรือไม่


4

ในกรณีที่มีคนอื่นลงจอดที่นี่จาก Google และถึงแม้ว่าคำถามนี้จะขอทุบตีโดยเฉพาะ แต่ก็เป็นอีกทางเลือกหนึ่ง:

คุณสามารถใช้zenity Zenity เป็นยูทิลิตี้กราฟิกที่สามารถใช้ภายในสคริปต์ทุบตี แต่แน่นอนว่าสิ่งนี้จะต้องใช้เซิร์ฟเวอร์ X เนื่องจากผู้ใช้ระบุว่าถูกต้อง

sudo apt-get install zenity

จากนั้นในสคริปต์ของคุณ:

RETVAL=`zenity --entry --title="Hi" --text="What is your username"`

ลิงค์ที่มีประโยชน์


3
ยกเว้นว่าไม่มีเซิร์ฟเวอร์ X
user877329

1
OP dialogต้องการทราบเกี่ยวกับ มันเหมือนกับว่าฉันมาและถามคุณว่า "ฉันจะเขียนสิ่งนี้และในไพ ธ อนได้อย่างไร" แต่คุณให้ฉันทุบตี - ฉันมีความสุขมากที่สามารถทำได้ในวิธีที่แตกต่างกัน แต่นั่นไม่ใช่สิ่งที่ฉันขอ
Sergiy Kolodyazhnyy

@Serg ความคิดเห็นของคุณไม่ถูกต้องคำตอบของฉันไม่ได้: ยูทิลิตี้ให้ทางเลือกที่ถูกต้องและเรียบง่ายอย่างสมบูรณ์แบบสำหรับวิธีการแก้ปัญหาที่ขอโดย OP
Wtower

3

คำตอบที่ได้รับจาก Sneetsher ค่อนข้างหรูหรากว่า แต่ฉันสามารถอธิบายได้ว่ามีอะไรผิดปกติ: ค่าของ$$มันแตกต่างกันภายใน backticks (เพราะมันเริ่มเชลล์ใหม่และ$$เป็น PID ของเชลล์ปัจจุบัน) คุณจะต้องใส่ชื่อไฟล์ในตัวแปรแล้วอ้างถึงตัวแปรนั้นแทน

#!/bin/bash
t=$(mktemp -t inputbox.XXXXXXXXX) || exit
trap 'rm -f "$t"' EXIT         # remove temp file when done
trap 'exit 127' HUP STOP TERM  # remove if interrupted, too
dialog --inputbox \
    "What is your username?" 0 0 2>"$t"
retval=$?
input=$(cat "$t")  # Prefer $(...) over `...`
case $retval in
  0)    echo "Your username is '$input'";;
  1)    echo "Cancel pressed.";;
esac

ในกรณีนี้การหลีกเลี่ยงไฟล์ชั่วคราวจะเป็นการแก้ปัญหาที่ดีกว่า แต่จะมีหลายสถานการณ์ที่คุณไม่สามารถหลีกเลี่ยงไฟล์ชั่วคราวได้

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