สคริปต์ Bash จะบอกได้อย่างไรว่ามันทำงานอย่างไร


10

ฉันมีสคริปต์ Bash ที่ฉันพยายามทำเพื่อช่วยให้ฉันเรียกใช้คำสั่งที่ค่อนข้างซับซ้อนและมีการเปลี่ยนแปลงเล็กน้อยซึ่งมันจะถามฉันเกี่ยวกับเสียงสะท้อนและการอ่าน

ฉันพบวิธีแก้ไขเพื่อบังคับให้รันเทอร์มินัลเพื่อเรียกใช้งานคำสั่ง แต่ฉันไม่สนใจสิ่งนั้น สิ่งที่ฉันต้องการให้ทำคือถ้าฉันว่างและกด Enter บนมันใน Nautilus (ทำให้มันรันด้วย Run Software) มันจะค่อยๆปรากฏขึ้นแจ้งเตือนว่า "กรุณาเรียกใช้จากเทอร์มินัล"

ฉันสามารถทำให้ป๊อปอัปเกิดขึ้นได้ดังที่ฉันรู้จักคำสั่ง - แต่ฉันไม่สามารถรับ Bash script เพื่อบอกได้ว่ามันทำงานอยู่ภายใน terminal หรือไม่ดูเหมือนว่าจะคิดเสมอ เป็นไปได้ไหม

คำตอบ:


10

จากman bashภายใต้การแสดงออกตามเงื่อนไข :

-t fd  
    True if file descriptor fd is open and refers to a terminal.

สมมติว่า fd 1 เป็นมาตรฐานif [ -t 1 ]; thenควรทำงานให้คุณ ขั้นสูงเชลล์ Scripting คู่มืออ้างว่า-tใช้วิธีนี้จะล้มเหลวมากกว่าsshและว่าการทดสอบ (ใช้ stdin, stdout ไม่ได้) ดังนั้นจึงควรจะเป็น:

if [[ -t 0 || -p /dev/stdin ]]

-pทดสอบว่ามีไฟล์อยู่หรือไม่และเป็นไพพ์ที่มีชื่อ อย่างไรก็ตามฉันทราบว่าการทดลองนี้ไม่เป็นความจริงสำหรับฉัน: -p /dev/stdinล้มเหลวสำหรับทั้งเทอร์มินัลปกติและเซสชัน ssh ในขณะที่if [ -t 0 ](หรือ-t 1) ทำงานในทั้งสองกรณี (ดูความคิดเห็น Gilles ด้านล่างเกี่ยวกับปัญหาในส่วนนั้นของคู่มือสคริปต์เชลล์ขั้นสูง )


หากปัญหาหลักคือบริบทเฉพาะที่คุณต้องการเรียกใช้สคริปต์เพื่อให้ทำงานในลักษณะที่เหมาะสมกับบริบทนั้นคุณสามารถเลี่ยงปัญหาทางเทคนิคเหล่านี้ทั้งหมดและช่วยตัวเองให้ยุ่งยากโดยใช้ wrapper และตัวแปรที่กำหนดเอง:

!#/bin/bash

export SPECIAL_CONTEXT=1
/path/to/real/script.sh

เรียกสิ่งนี้live_script.shหรืออะไรก็ได้แล้วดับเบิ้ลคลิกแทน แน่นอนว่าคุณสามารถทำสิ่งเดียวกันให้สำเร็จด้วยอาร์กิวเมนต์บรรทัดคำสั่ง แต่ยังจำเป็นต้องใช้ wrapper ในการชี้และคลิกในไฟล์ GUI ของเบราว์เซอร์


5
นี่เป็นคำตอบที่ถูกต้อง - เป็นวิธีที่ POSIX บอกว่าเชลล์ควรตรวจพบว่ามันเป็นแบบโต้ตอบหรือไม่
mikeserv

2
@DanielAmaya - หากคุณเปลี่ยนเส้นทางอินพุตสคริปต์จะไม่ถูกเรียกใช้บนเทอร์มินัล คำถามคือวิธีการตรวจสอบว่าสคริปต์จะทำงานใน terminal
mikeserv

2
คุณแน่ใจเกี่ยวกับการใช้||ภายใน[ … ]เช่นนั้นหรือไม่ ถ้าคุณใช้[[ … ]]มันจะดี แต่โดยปกติแล้ว||จะใช้เพื่อแยกคำสั่งและ[ -t 0เป็นการเรียกที่ไม่ถูกต้อง[เพราะมัน]หายไปล่าสุด โดยทั่วไปจะไม่มีคำสั่ง-pเช่นกัน ฉันเห็นด้วยกับการทดสอบเครื่อง; นั่นอาจเป็นวิธีที่จะทำ เป็นเพียงไวยากรณ์ที่ฉันกังวล
Jonathan Leffler

1
@ JonathanLeffler ถูกต้อง; ที่ควรสร้างข้อผิดพลาดทางไวยากรณ์เนื่องจากตัวดำเนินการเชลล์||เห็นก่อน]อาร์กิวเมนต์สุดท้ายที่[ต้องการ
chepner

3
ส่วนนั้นจากคู่มือการใช้สคริปต์การทุบตีขั้นสูงมีข้อผิดพลาดหลายประการ PS1ไม่ใช่การทดสอบที่เชื่อถือได้เพื่อบอกว่าเชลล์เป็นแบบโต้ตอบหรือไม่ “ หากสคริปต์ต้องการทดสอบว่ามันกำลังทำงานอยู่ในเชลล์แบบโต้ตอบหรือไม่” ก็เกิดความสับสนด้วย: มันควรจะเป็นถ้าบางรหัสจำเป็นต้องทดสอบ - สคริปต์มักจะไม่ทำงานในเชลล์แบบโต้ตอบ (แต่อาจเป็นได้ถ้ามันมา) . การทดสอบiใน$-เป็นวิธีที่ถูกต้องในการทดสอบว่าเชลล์นั้นมีการโต้ตอบหรือไม่ การทดสอบ-t 0หรือ-t 2เป็นวิธีที่ถูกต้องในการบอกว่าสคริปต์ทำงานในเทอร์มินัลซึ่งแตกต่างจากการโต้ตอบหรือไม่
Gilles 'หยุดชั่วร้าย'

0

ใช้ตัวแปร bash $ SHLVL เพื่อตรวจสอบระดับของการทำรังของเชลล์ ในการรันสคริปต์ 'raw' โดยการดับเบิลคลิกจะเป็น 1 ในสคริปต์ที่รันภายในเทอร์มินัลจะเป็น 2

#!/bin/bash
if (( SHLVL < 2 )) ; then
    echo "Please run this from a terminal."
    read -p "Press <Enter> to close this window"
    exit 1
fi
# rest of script

0

แม้ว่าคำตอบของ goldilocks อาจจะถูกต้องในกรณีทั่วไป แต่ดูเหมือนว่ามีกรณีขอบ ในกรณีของฉันเอง xserver ของฉันได้รับการกำหนดค่าให้เริ่มต้นจากtty1และไม่เคยปล่อยให้ tty นั้น หาก Xorg's stdoutเป็น TTY ดูเหมือนว่าไคลเอ็นต์จะมี TTY นั้นเชื่อมโยงกับตัวให้คำอธิบายไฟล์ของพวกเขาตามค่าเริ่มต้น

นี่คือวิธีที่ฉันแก้ไขปัญหาของฉัน:

#!/bin/bash
isxclient=$( readlink /dev/fd/2 | grep -q 'tty' && [[ -n $DISPLAY ]] ; echo $? )
if [[ ! -t 2  || $isxclient == "0" ]]; then
        notify-send "Script wasn't started from an interactive shell"
else
        echo "Script was started from an interactive shell"
fi

ฉันยังไม่ได้ทดสอบสิ่งนี้เพื่อดูว่ามันใช้งานกับการกำหนดค่า X มาตรฐานมากกว่านี้ได้หรือไม่และฉันยังสงสัยอย่างมากว่านี่เป็นเคสแบบขอบเท่านั้น หากใครพบวิธีแก้ปัญหาที่เหมาะสมกว่านี้โปรดกลับมาและบอกเรา


-2

$-อีกโดยใช้ตัวแปรภายในตัวเลือกทุบตีตั้ง

จาก.bashrc,

# If not running interactively, don't do anything
case $- in
    *i*) ;;
    *) return;;
esac

เชลล์เชิงโต้ตอบไม่จำเป็นต้องเชื่อมต่อกับเทอร์มินัล cmd | sh -i | cmdขณะที่หนึ่งเริ่มต้นด้วยการเชื่อมต่อที่มีการเริ่มต้นโดยอัตโนมัติโต้ตอบนี้ยังเป็นไปได้ที่:
mikeserv

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