Bash betiği nasıl çalıştırıldığını nasıl anlayabilir?


11

Bana yankı ve okuma ile soracak küçük değişikliklerle oldukça karmaşık bir komut çalıştırmak yardımcı olmak için yapmaya çalışıyorum bir Bash komut dosyası var.

Komutu yürütmek için bir terminal çalıştırmaya zorlayacak çözümler buldum, ama bununla ilgilenmiyorum. Yapmak istediğim şey, eğer boşluk bıraksam ve Nautilus'ta Enter'a basarsam (Run Software ile çalışmasını sağlayarak), "Lütfen bunu bir terminalden çalıştır" diyen bir bildirim açar.

Ben pop-up gerçekleşmesi alabilirsiniz - ben komut biliyorum gibi - ama bir terminal içinde çalıştırılıp çalıştırılmadığını söylemek için Bash betiği alamıyorum, her zaman öyle görünüyor. Hatta mümkün mü?

Yanıtlar:


10

Gönderen man bashaltında ŞARTLI ANLATIM :

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

Fd 1'in standart olarak kabul if [ -t 1 ]; thenedilmesi, sizin için çalışmalıdır. Gelişmiş Shell Scripting Guide iddiaları -tbu şekilde kullanılan başarısız olur sshve testin ki (Stdin kullanarak değil stdout'u) bu nedenle olmalıdır:

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

-pbir dosyanın var olup olmadığını ve adlandırılmış bir kanal olup olmadığını test eder. Bununla birlikte , deneyimsel olarak bunun benim için doğru olmadığını not ederim: -p /dev/stdinhem normal terminaller hem de ssh oturumları için başarısız olurken if [ -t 0 ](veya -t 1) her iki durumda da çalışır ( Gelişmiş Kabuk Komut Dosyası Kılavuzu'nun bu bölümündeki sorunlar hakkında aşağıdaki Gilles yorumlarına bakın ).


Birincil sorun, bu bağlama uygun bir şekilde davranması için komut dosyasını çağırmak istediğiniz özel bir bağlamsa, bir sarmalayıcı ve özel bir değişken kullanarak tüm bu teknikleri kaldırıp kendinize biraz yaygara kaydedebilirsiniz:

!#/bin/bash

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

Buna live_script.shya da her neyse çağırın ve bunun yerine çift tıklayın. Elbette aynı şeyi komut satırı argümanlarında da yapabilirsiniz, ancak bir GUI dosya tarayıcısının çalışmasını sağlamak ve tıklatmak için bir sarıcıya ihtiyaç duyulur.


5
bu doğru cevaptır - POSIX bir kabuğun etkileşimli olup olmadığını nasıl algılaması gerektiğini de söyler.
mikeserv

2
@DanielAmaya - girişi yeniden yönlendirirseniz komut dosyası bir terminalde çalıştırılmaz. Soru, komut dosyasının bir terminalde çalıştırılıp çalıştırılmadığını nasıl tespit edeceğinizdir.
mikeserv

2
Bunun ||içinde kullanımından emin misiniz [ … ]? Eğer kullanırsanız [[ … ]]iyi olur, ancak normalde ||komutları ayırmak için kullanılır ve sonuncusu eksik [ -t 0olduğu için yanlış bir çağrıdır . Genellikle bir komut da yoktur. Bir terminalin testine katılıyorum; muhtemelen bunu yapmanın yolu budur. Bu sadece endişelendiğim sözdizimidir. []-p
Jonathan Leffler

1
@JonathanLeffler Doğru; Kabuk operatörü ||istenen son ]argümandan önce görüldüğü için sözdizimi hatası üretmelidir [.
chepner

3
Gelişmiş Bash-Komut Dosyası Kılavuzu'ndaki bu bölümün birkaç hatası vardır. PS1kabuğun etkileşimli olup olmadığını söylemek için güvenilir bir test değildir. “Bir komut dosyasının etkileşimli bir kabukta çalışıp çalışmadığını test etmesi gerekiyorsa” kafa karıştırıcıdır: bazı kodların test edilmesi gerekiyorsa da olmalıdır - bir komut dosyası genellikle etkileşimli bir kabukta çalışmaz (ancak kaynaklanıyorsa olabilir) . İçin test iin $-kabuk interaktif ise testine doğru yoldur. Test etme -t 0veya -t 2komut dosyasının etkileşimli olmaktan farklı bir terminalde çalışıp çalışmadığını söylemenin doğru yoludur.
Gilles 'SO- kötü olmayı kes

0

Kabuk yuvalama düzeyini algılamak için bash $ SHLVL değişkenini kullanın. 'Raw' komut dosyasını çift tıklatarak çalıştırdığınızda 1, terminal içinde çalışan bir komut dosyasında 2 olacaktır.

#!/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

Her ne kadar goldilocks'ın cevabı tipik olarak doğru olsa da, kenar vakalar var gibi görünüyor. Kendi durumumda, xserver'ım başlamak üzere yapılandırılmış tty1ve asla bu tty'den çıkmıyor. Xorg's stdoutbir TTY ise, istemciler varsayılan olarak TTY dosya tanımlayıcılarına bağlı olacak gibi görünüyor.

Sorunumu şu şekilde çözdüm:

#!/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

Daha standart bir X konfigürasyonunda çalışıp çalışmadığını görmek için bunu test etmedim ve bunun tek kenar durum olduğundan da çok şüpheliyim. Herkes daha genel olarak uygulanabilir bir çözüm bulursa, lütfen geri dönün ve bize bildirin.


-2

Bir diğeri, bash seçeneklerini kullanarak dahili değişkeni ayarlar $-.

Gönderen .bashrc,

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

etkileşimli bir kabuk mutlaka bir terminale bağlı değildir. Bu bağlamda başlayan biri otomatik interaktif başladı iken, bu da mümkündür: cmd | sh -i | cmd.
mikeserv

Bu kod bir komut dosyasında yürütülüyor. Bir terminalde çalışıyor olsa bile etkileşimli olmayacaktır.
Gilles 'SO- şeytan olmayı bırak'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.