Skocz do zawartości
atsiv

Bash + Zenity - skrypty bash w trybie graficznym

Rekomendowane odpowiedzi

Ostatnio postanowiłem pisać skrypty w bashu, który będzie wyświetlać okienka w trybie graficznym. Za wszystko odpowiada zenity i utworzyłem coś podobnego jak na obrazku:

http://rafal.drezek.info/wp-content/uploads/2009/05/okienko-wyboru.jpg

 

Wszystko fajnie, wszystko działa, ale denerwuje mnie ten pasek wybierz/odpowiedź. Czy da się go jakoś usunąć lub zablokować, ponieważ gdy kliknę np. na odpowiedź, wszystkie opcje są sortowane alfabetycznie, a ja nie chcę żeby tak mi się robiło. Wie ktoż może, bo nie mogę znaleźć nic na ten temat?

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Hmm.. jeśli nie wstawię tekstu i kliknę na to pole, to sortuje wpisy na liście alfabetycznie, właśnie to mi przeszkadza trochę, bo chciałbym, aby przynajmniej on nie działał skoro nie da się go usunąć.

Edytowane przez atsiv

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

Hmm.. jeśli nie wstawię tekstu i kliknę na to pole, to sortuje wpisy na liście alfabetycznie, właśnie to mi przeszkadza trochę, bo chciałbym, aby przynajmniej on nie działał skoro nie da się go usunąć.

 

Zenity to nie jest graficzne API dla basha - to prosty sposób na graficzną interakcję. IMO masz 2 wyjścia: zmodyfikować żródło Zenity lub poprostu użyć listy z numerkami: "1. cośtam, 2. inne cośtam" ;)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Wiem, wiem :)

 

A tak na marginesie, nie chcę zakładać nowego tematu, ponieważ to również dotyczy basha.

 

Załóżmy, że mam taką funkcję:

 

pobierz(){sudo aptitude update}aktualizuj(){sudo aptitude upgrade}aktualizujjeden(){sudo aptitude dist-upgrade}zrob(){echo 'prosze czekac'$*echo 'zakonczono'read}

Teraz chciałbym, aby skrypt zrobił coś takiego:

 

zrob pobierz

Działa. A teraz chciałbym zrobić coś takiego:

 

zrob pobierz aktualizuj aktualizujjeden

Już nie. Jak to zrobić, żeby to działało? Czytałem o zmiennej IFS w internecie i że tym można zrobić, żeby to zadziało ale nie wychodzi mi.

Edytowane przez atsiv

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

...

zrob(){echo 'prosze czekac'$*echo 'zakonczono'read}
Czytałem o zmiennej IFS w internecie i że tym można zrobić, żeby to zadziało ale nie wychodzi mi.
zrob() {IFS='; 'echo 'prosze czekac'e.val "$*" echo 'zakonczono'read}evaluateuate << co to za shit?
#!fuck! e.v.a.l to nie jewane "evaluate", tym bardziej w tagach

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Wielkie dzięki, załapałem wreszcie to, może instrukcja Twoja jest krótka, ale zrozumiała :) Powiem Ci, że teraz inaczej to widzę niż wcześniej, ponieważ mój znajomy jak tłumaczył mi to, aż się zamotałem ;)

Edytowane przez atsiv

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Tak na marginesie czy ten IFS jest potrzebny, bo mi bez tego również działa? ;)

 

PS. Na prośbę znajomego, który też poznaje basha. Swój skrypt uruchamia za pomocą sudo: sudo skrypt.sh. Jeśli wybierze opcję gconf-editor to wiadomo, że zmiany wtedy będą dotyczyć konta root. Czy dałoby się zrobić jakieś polecenie lub funkcję, która będzie uruchamiać gconf-editor na zwykłym użytkowniku, na którym teraz się pracuje? Np. ktoś jest zalogowany na koncie 'Dom', odpala skrypt na koncie root, ale chciałby żeby skrypt jedną rzecz wykonał na zwykłym koncie i potem dalej pracował na roocie.

Edytowane przez atsiv

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

Tak na marginesie czy ten IFS jest potrzebny, bo mi bez tego również działa? ;)

Dziala? hmm...wrzuć to w plik.sh i odpal:
#!/bin/bashfn1() {echo "Fn1"}fn2() {echo "Fn2"}fn3() {echo "Fn3"}run() {evaluateuate "$*" #e.v.a.l. }IFS=" " #default valueecho "IFS=\" \" test: run fn1 fn2 fn3"run fn1 fn2 fn3IFS=";" #IFS set to semicolon - command separatorecho "IFS=\";\" test: run fn1 fn2 fn3"run fn1 fn2 fn3IFS=" " #IFS restoreexit 0
;)

 

Co do Gconf: nie bardzo jarzę po co takie rozwiązanie - imo bez sesnsu, ale jeśli już to przecież jest to banalne: >su [user] [programm]; exit ;)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

To wtedy co innego i tutaj IFS już się przydaje :)

 

Jeśli chodzi o zwykłe konto i root, on robi 99% rzeczy na koncie root i 1% chciał zrobić na zwykłym koncie ;) Ja na ogól trzymam się innej praktyki, ale ona ma inne widocznie wymagania.

 

A jeszcze jedno pytanie:

 

aktualizujos(){gksu aptitude updategksu aptitude upgradegksu aptitude dist-upgrade}aktualizujos | zenity --progress --pulsate

Gdybym dał samo 'aktualizujos', wtedy ładnie by ta funkcja zadziałała, ale jak dołożę zenity już coś nie... gdzie tu jest błąd?

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>
#!/bin/bashfn4() {echo -e "\n5% \n#Updating...";sleep 1.5echo -e "\n33% \n#Upgrading..."; sleep 1.5echo -e "\n66% \n#Upgrading..."; sleep 1.5echo -e "\n100% \n#Done"}fn4 |zenity --progressexit 0
... chyba wypadało by coś wysłać do progress bara ;)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

fn4() {echo -e "\n5% \n#Updating..."; sleep 1.5gksudo 'aptitude update'echo -e "\n33% \n#Upgrading..."; sleep 1.5gksudo 'aptitude -y upgrade'echo -e "\n66% \n#Upgrading..."; sleep 1.5gksudo 'aptitude -y dist-upgrade'echo -e "\n100% \n#Done"}fn4 | zenity --progressexit 0

Zrobiłem, tzn. przerobiłem Twój kod i chyba będzie działać, bo na razie nie mam jak sprawdzić.

Edytowane przez atsiv

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

heh, ten przykład miał na celu jedynie pokazanie sposobu wysyłania danych do zenity ;) Oczywiście Twoja przeróbka będzie działać, ale to kiepskie rozwiązanie. Porządny skrypt powinien wyciągnąć dane z aptitude, przliczyć % z aptitude na % całości i dopiero takie coś pokazać użytkownikowi.

 

edit: aaa, no i po co Ci to sleep? ;)

Edytowane przez tomazzi

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

żeby o 1,5 sekundy było opóźnienie, a tak na serio tak tylko przypadkowo jest :) jeśli chodzi o te % aż tak dokładnie nie musi być ;) ale wget umiem namówić aby pokazywał dokładnie w procentach ile pobrało się, w przypadku aptitude nigdy nie sprawdzałem.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Zrobiłem skrypt, a właściwe przerobiłem czyjś:

 

- while ...- menu główne: zenity z radiolist- case (1), 2), 3) itd.)

Mogę powiedzieć tylko tyle, że działa. Ale zamiast radiolist chcę dać checklist, gdy wybieram kilka pozycji już nie i nie wiem dlaczego tak się dzieje?

Edytowane przez atsiv

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

Mogę powiedzieć tylko tyle, że działa. Ale zamiast radiolist chcę dać checklist, gdy wybieram kilka pozycji już nie i nie wiem dlaczego tak się dzieje?

...bo zenity wymaga odpowiedniej składni. Poza tym wypadałoby podać nieco bardziej cośmówiący fragment skryptu... ;)

Ogólnie checkbox-lista powinna wyglądać jakoś tak:

#!/bin/bashcolumndesc='--column "" --column "Name" --column "Describtion"'list=' \. row1 desc1 \. row2 desc2 \. row3 desc3 \. row4 desc4'ev.al "zenity --list --multiple --checklist --text="Select" $columndesc $list "; exit 0

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Zrobiłem sonie taki skrypt:

 

echo "podaj wyrazy:"read 1wyr 2wyr 3wyrecho "podałeś: $1wyr $2wyr 3$wyr"

pies kto kaczka - działa

 

pies kot tygrys lampart kaczka - jak zrobić żeby kot, tygrys, lampart były tam gdzie $2wyr?

 

oraz skrypt z zenity:

 

zenity --entry | read 1wyr 2wyr 3wyrzenity --info "podałeś: $1wyr $2wyr 3$wyr"
Ten drugi kompletnie mi nie działa. Jak poprawnie powinien wyglądać?

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

pies kot tygrys lampart kaczka - jak zrobić żeby kot, tygrys, lampart były tam gdzie $2wyr?

Ten "problem" można rozwiązać na wiele sposobów, ale podam najbardziej uniwersalny, oparty na tablicach:

#!/bin/bashread -a usrinputnumwords=${#usrinput[@]}; lastindex=$((numwords-1))echo -en "entered: \"${usrinput[*]}\" , =$numwords words, last index=$lastindex\n"#print array elementsecho -en "\nlist words in array:\n"n=0while (( n <= lastindex ));do	echo -en "word($n)= \"${usrinput[$n]}\"\n"	(( n++ ))done#do the trick ;)word1=${usrinput[0]}word3=$(echo ${usrinput[$lastindex]})#"remove" element 0 and last from array:usrinput[0]=""; usrinput[$lastindex]=""word2=${usrinput[*]}echo -en "\nword1=$word1 \nword2=$word2 \nword3=$word3\n\n"exit 0

:P

 

... a co do zenity: warto przeczytać man do końca, gdzie pisze coś o opcji --text= ;)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Mam mały i nowy problem, z którym walczę od kilku dni. Załóżmy, że mam skrypt, który aktualizuje system apt-getem:

 

( sudo apt-get updatesudo apt-get upgrade ) | zenity --progress --pulsateif [ $? = 0 ]   sudo killall apt-get   zenity --errorelse   zenity --infofi

Ogólnie działa, ale nie tak jak ja bym chciał, ponieważ:

1) zenity od razu nie pulsuje, tylko po kilku sekundach, czy da się zrobić, aby od razu to robił?

2) gdy nacisnę na przycisk Cancel skrypt nie zabija apt-geta, tzn. czeka gdy skończy działać upgrade i dopiero wtedy zadziała killall, a ja chcę żeby to polecenie zadziałało w trakcie działania apt-get, a nie po, da się tak zrobić? Tzn. wiem, że istnieje coś takiego jak auto-kill, ale gdy chce aby skrypt informował o błędzie to coś nie działa on...

Edytowane przez atsiv

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

1. Wkraczasz na bardzo niebezpieczy grunt używając killall w stosunku do apta.

2. U mnie pulsate działa od razu, po wpisaniu >sudo apt-get update | zenity --progress --pulsate.

Słów kilka na ten temat:

--pulsate jest specyficznym trybem oznaczającym "nie wiem ile czasu do końca, ale żyję" ;)

Jeśli pipe wyśle jedną daną o wartości "0%" pulsate nie zadziała, ponieważ używay jest tryb "determinate mode", czyli z określonymi wartościami: max i aktualną. "Indeterminate mode" (--pulsate) włącza się automatycznie po pewnym czasie - jeśli nie pojawią się kolejne dane wejściowe.

3. "Subprocess" nie może zabić "parent process" a już na pewno nie w taki sposób jak Twój.

Jedyną opcją jest użycie "process substitution" oraz apta w tle -> musisz mieć jakiś działający proces nadrzędny względem apt.

 

edit: ...co w Tym przypadku sprowadza się do dopisania "&" w nawiasach obejmujących apt ;)

...forking in subshell, brakuje tylko evaluateuate i exec do kompletu... ;)

Edytowane przez tomazzi

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Albo można zrobić tak:

 

( apt-get update ; apt-get upgrade ) | ( if [ ! `zenity --progress --pulsate` ]

then

kill apt-get

fi )

 

Ale tak jak pisałeś dla "apta" to jest niebezpieczne i masz tutaj rację. A dałoby się Twoim zdaniem zrobić coś takiego, że przycisk Anuluj nic by nie robił, tzn. klikam na niego, a "progress" dalej sobie pulsuje, zamiast wyłączyć okienko.

 

Hmm a jak jest z output? Czy wynik wyjściowy można odczytać tylko z pliku?

 

I jeszcze jedno malutkie pytanie, załóżmy sobie, że masz funkcję:

 

costam {

blablabla

$*

}

 

i jak chce zrobić coś takiego:

 

costam `apt-get update

apt-get upgrade`

 

to coś nie łapie... co tu źle robię?

Edytowane przez atsiv

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

costam `apt-get update

apt-get upgrade`

 

to coś nie łapie... co tu źle robię?

o ile dobrze rozumiem problem - to już to przerabialiśmy -> IFS...

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

3. "Subprocess" nie może zabić "parent process" a już na pewno nie w taki sposób jak Twój.

Jedyną opcją jest użycie "process substitution" oraz apta w tle -> musisz mieć jakiś działający proces nadrzędny względem apt.

 

edit: ...co w Tym przypadku sprowadza się do dopisania "&" w nawiasach obejmujących apt ;)

...forking in subshell, brakuje tylko evaluateuate i exec do kompletu... ;)

Sorki, że po takim czasie wracam do tego punktu, ale Tobie chodziło o coś takiego prawda:

exec 3> >(zenity --progress --pulsateifkillfi)aplikacja >&3exec 3>&-
albo:

(sudo apt-get update &) | zenity --progress --pulsate
Edytowane przez atsiv

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

No mniej więcej, ale to co napisałeś nie jest bezpieczne.

Coś u mnie nie chce działać wercja 2 -> ale jestem już mocno znietrzeźwiony, więc sprawdzę jutro...

;)

... czyli dzisiaj

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

U mnie 2ga wersja działa

heh, u mnie też ale mi na wzrok padło...

 

a może tak:

#!/bin/bashdeclare tmpsdeclare usrbutton( { #foreground blockwhile read tmps; do	echo $tmps	if [ "$tmps" == "80%" ]; then		break	fi	read -t 0.1 usrbutton <&2	if [ "$usrbutton" == "cancel" ]; then		break	fidone; } ) < <( { #bg block 1        i=0	while [ $i -lt 101 ]; do			echo "$i%"			sleep 0.5			((i+=10))	done; } & ) > >( { #bg block 2			zenity --progress --auto-close			if [ $? == 1 ]; then				echo "cancel" >&2			fi		} & )exit 0

bg block 1 - aplikacja dająca "procenty" (nie mylić z moderatorem) ;)

zenity return status == 1 wypluty do stderr

"foreground block" przerywa działanie przy 80% lub po odczytaniu "cancel" z stderr.

 

Oczywistą "niedoróbką" jest użycie stderr zamiast dedykowanego FD - w pewnych sytuacjach "cancel" może być nadpisane przez inną wartość.

Edytowane przez tomazzi

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Ło ale kod strzeliłeś :) ale biorąc pod uwagę bezpieczne sytuacje, myślę że wystarczy prosty kod z killallem.

 

A tak na marginesie czytam kurs o zenity i zastanawia mnie jedna rzecz, 1 oznacza anuluj, 0 ok, a -1 powinno znaczyć, że coś nie zostało zaznaczone... Właśnie utworzyłem zenity list (tabela | zenity list ...), przycisk 1 i 2 działają, ale jak nic nie zaznaczę to zamiast -1 z informacją, że nic nie zostało zaznaczone, uaktywnia mi się przycisk 1. Coś źle robię? Mało tego był tam gotowy skrypt i on u mnie też nie działa jak oczekuję.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

...zwykłe process substitution w dwóch kierunkach + "bypass" przez stderr ;)

 

Link do skryptu lub istotny fragment? - było by zdecydowanie łatwiej...

Edytowane przez tomazzi

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dołącz do dyskusji

Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.

Gość
Dodaj odpowiedź do tematu...

×   Wklejono zawartość z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Odnośnik został automatycznie osadzony.   Przywróć wyświetlanie jako odnośnik

×   Przywrócono poprzednią zawartość.   Wyczyść edytor

×   Nie możesz bezpośrednio wkleić grafiki. Dodaj lub załącz grafiki z adresu URL.

Ładowanie


×
×
  • Dodaj nową pozycję...