Czy powłoka interaktywna może stać się nieinteraktywna lub odwrotnie?

16

Czy powłoka interaktywna może stać się nieinteraktywna lub odwrotnie?

Uwaga: Przeprowadziłem wiele badań dotyczących podstawowego pytania „Jaka jest różnica między interaktywnym a nieinteraktywnym?”, A wyniki moich badań skłoniły mnie do zadania tego pytania.

To pytanie ma długą preambułę, ponieważ kluczowe znaczenie ma to, jakiego rodzaju definicji używamy do określenia „interaktywny”, aby na nie odpowiedzieć. Definicja może być dowolną etykietą dla określonego zestawu; może opisywać różne właściwości; lub może dać ci informacje, których możesz użyć, aby przewidzieć zachowanie i zrozumieć cel. Ten ostatni typ możemy nazwać „definicją akcji” lub „definicją dynamiczną” i jest najbardziej przydatny.


W man 1p shpodana jest następująca definicja interaktywnej powłoki:

   If the -i option is present, or  if  there  are  no  operands  and  the
   shells  standard  input and standard error are attached to a terminal,
   the shell is considered to be interactive.

Od wzmianki o „opcji -i” i użyciu słowa „operandy”, odnosi się to do wywołania powłoki , a nie atrybutów, które można zbadać w działającej powłoce.

Strona podręcznika użytkownika Bash wyraża to nieco inaczej:

   An interactive shell is one started without  non-option  arguments  and
   without the -c option whose standard input and error are both connected
   to terminals (as determined by isatty(3)), or one started with  the  -i
   option.   PS1 is set and $- includes i if bash is interactive, allowing
   a shell script or a startup file to test this state.

Definicja w pierwszym zdaniu ponownie odnosi się tylko do początku powłoki.

Drugie zdanie (w moim czytaniu) określa warunki, które są używane jako proxy do ustalenia, czy powłoka została uruchomiona w określony sposób, który jest zdefiniowany jako „interaktywny”.

Zauważ, że ja nie interpretują to zdanie jako: „bash powłoka jest interaktywna wtedy i tylko wtedy $-, zawiera«i»” $-wydaje się po prostu przydatnym wskaźnikiem, a nie definicją interaktywnego. Ma to zasadnicze znaczenie dla mojego pytania.


Oba ( shdefinicja POSIX i Bash) są definicjami mechanicznymi, które określają, w jakich okolicznościach etykieta „interaktywna” dotyczy powłoki, którą uruchomiłeś. Nie są to definicje akcji, ponieważ nie dają żadnych implikacji tej etykiety.

Widzę jednak, że w pozostałej części strony podręcznika Bash są posypane odniesienia do powłoki zachowującej się w określony sposób „chyba, że ​​jest to powłoka interaktywna” lub „tylko w powłokach interaktywnych lub jeśli ustawiona jest opcja _____”. (Istnieje wiele przykładów i to nie jest główny punkt tego pytania).

Przyjmuję więc do wiadomości, że „interaktywny” jest po prostu wygodną etykietą do zbioru domyślnych „interaktywnych” zachowań (ustawień opcji) opisanych na pozostałej stronie strony man. Sam w sobie nie jest podstawowym terminem ani przedmiotem; nie ma autorytatywnej definicji poza kodem źródłowym powłoki. (W przeciwieństwie do na przykład terminów „otwarty deskryptor pliku” lub „zatrzymany proces”, które odnoszą się do abstrakcji wbudowanych w projekt samego jądra.)

(Chociaż jest to również zdefiniowane w definicji POSIX sh, ta strona man [ man 1p sh] ma znacznie mniej zastosowań „chyba, że ​​powłoka jest interaktywna” i podobnych instrukcji niż man bash, i prawie wyłącznie skupia się na różnicach czasu wywołania, więc skupię się na Bash od tego momentu.)


Niektóre z implikacji, że powłoka jest „interaktywna”, i tak są istotne tylko w czasie wywołania , na przykład pliki, które są pozyskiwane przez powłokę przed odczytaniem innych poleceń. Jednak nie implikacje (przynajmniej w Bash), które są istotne w każdej chwili. Dlatego musi istnieć sposób na określenie, dla dowolnej działającej powłoki, czy jest ona interaktywna czy nie.

Uruchomienie set +iw interaktywnej powłoce Bash powoduje usunięcie „i” z zawartości $-.

Pytanie brzmi: czy to faktycznie oznacza, że ​​powłoka nie jest już interaktywna?

Dokładna definicja Basha nie powinna, ponieważ nigdzie w definicji nie jest wymagane, aby „i” występował w $-:

   An interactive shell is one started without  non-option  arguments  and
   without the -c option whose standard input and error are both connected
   to terminals (as determined by isatty(3)), or one started with  the  -i
   option.

Dokładne odczytanie dokładnej definicji rodzi również pytanie: jeśli przekierowanie stdin lub stderr terminala interaktywnego zostanie przekierowane, aby nie były już podłączone do terminali, to czy powłoka stanie się nieinteraktywna?

( Wygląda na to, że odpowiedź na to pytanie brzmi „nie”, a strona podręcznika mogła zawierać modyfikator: „którego standardowe wejście i błąd są podłączone do terminali ... w momencie wywołania ”, ale nie wiem ostatecznie.)


Jeśli odpowiedź brzmi: „Nie, powłoka nie może stać się nieinteraktywna ani odwrotnie”, to jaki jest ostateczny sposób ustalenia, czy powłoka jest interaktywna?

Mówiąc jeszcze inaczej: Jeśli istnieją zachowania „interaktywnej powłoki”, które utrzymują się po set +i, to co jest używane do ustalenia, że ​​te zachowania powinny nadal obowiązywać?


Aby ktokolwiek w to wątpił: istnieją zachowania powłoki wywoływane interaktywnie, które trwają po set +ii zachowania powłoki wywoływane nieinteraktywnie, które utrzymują się później set -i. Na przykład rozważ następujący fragment man bash:

COMMENTS
   In a non-interactive shell, or an interactive shell in which the inter-
   active_comments  option  to  the  shopt  builtin  is enabled (see SHELL
   BUILTIN COMMANDS below), a word beginning with # causes that  word  and
   all  remaining  characters  on that line to be ignored.  An interactive
   shell without the interactive_comments option enabled  does  not  allow
   comments.  The interactive_comments option is on by default in interac-
   tive shells.

Tak więc, wyłączając tę interactive_commentsopcję, widzimy różnicę między powłokami interaktywnymi i nieinteraktywnymi. Trwałość tej różnicy pokazuje następujący skrypt:

#!/bin/bash

# When the testfile is run interactively,
# all three comments will produce an error
# (even the third where 'i' is not in '$-').
# When run noninteractively, NO comment will
# produce an error, though the second comment
# is run while 'i' IS in '$-'.

cat >testfile <<'EOF'
shopt interactive_comments
shopt -u interactive_comments
shopt interactive_comments
echo $-
#first test comment
set -i
echo $-
#second test comment
set +i
echo $-
#third test comment
EOF

echo 'running bash -i <testfile'
bash -i <testfile
echo 'running bash <testfile'
bash <testfile

Potwierdza to, że „interaktywne” i „ma iwartość $-nie są równoważne.

Podobny test ${parameter:?word}z użyciem parametru nieustawionego daje podobne wyniki, ponownie potwierdzając, że $-nie jest to „źródło prawdy” dla interaktywności powłoki.


Wreszcie, gdzie jest przechowywana ostateczna cecha „interaktywności” powłoki?

I czy interaktywna powłoka może stać się nieinteraktywna lub odwrotnie? (... zmieniając tę ​​cechę?)

Dzika karta
źródło
To pytanie jest również omawiane na czacie .
Wildcard

Odpowiedzi:

9

Pytanie, które zadałbym, brzmiałoby: dlaczego ktoś miałby to zrobić?

Możesz wyłączyć niektóre aspekty interaktywnych powłok, takie jak:

  • PS1= PS2= aby wyłączyć monity
  • set +m aby wyłączyć kontrolę zadań
  • wyłącz historię w niektórych powłokach
  • możesz być w stanie rozładować zlei wszystkie moduły ukończenia do zsh.

Ale jeśli chcesz, aby powłoka przestała być interaktywna, możesz zamiast tego:

. /some/file; exit

Aby przekazać resztę poleceń /some/file(zamień na, /dev/ttyjeśli nadal chcesz, aby polecenia były odczytywane z urządzenia tty), choć nadal istnieją pewne różnice w stosunku do nieinteraktywnych powłok, na przykład zachowanie returnlub fakt że nadal będzie kontrolować pracę lub:

exec myshell /dev/tty

Aby zastąpić bieżącą powłokę interaktywną powłoką nieinteraktywną, która nadal odczytuje polecenia z urządzenia tty.

Zauważ, że w przypadku bash 4.4, set +izwraca z bash: set: +i: invalid optionpodobnym w większości innych powłok.

Stéphane Chazelas
źródło
Absolutnie zgodził się, że byłoby to śmieszne . Moja koncepcja „interaktywnego”, jak wspomniałem, polega na tym, że jest to tylko zbiór domyślnych zachowań, które są użyteczne podczas interakcji z powłoką. Jeśli możesz zmienić każde z tych zachowań osobno i zmienisz każde z nich, to pytanie „Czy to wciąż jest interaktywna powłoka?” jest po prostu absurdalną semantyką; to nawet nie jest ważne pytanie. Jednak ....
Wildcard
1
@Wildcard, jeśli robisz to exec < <(sleep infinity)w interaktywnej powłoce, masz interaktywną powłokę, która nie jest bardzo interaktywna. Powłoka nadal uważałaby się za interaktywną, $-która zawierałaby i, ale może nie. Nie jestem pewien, czy jest o wiele więcej do omówienia.
Stéphane Chazelas
2
@Wildcard, jeśli powłoka została uruchomiona jako interactive, pozostanie taka. Fakt, że można to zrobić set +iw starszych wersjach bash, był błędem.
Stéphane Chazelas
1
@Wildcard, jeśli spojrzysz na kod źródłowy bash, prawdopodobnie zauważysz, że istnieje interactiveglobalna zmienna boolowska, która jest odwzorowana na iflagę $-. Zmiana wartości logicznej nie spowoduje automatycznej zmiany wszystkich zachowań interaktywnych powłok. Zmiana z interaktywnej na nieinteraktywną nie jest obsługiwana.
Stéphane Chazelas
4
@Wildcard Dash akceptuje set +ii przestaje wyświetlać monit. Jest to coś, czego użytkownik nie powinien robić, więc nie jest zaskakujące, że zachowanie zależy od powłoki i często jest przypadkowe, a nie wynikiem świadomej decyzji implementatora powłoki.
Gilles „SO- przestań być zły”