Czy powłoka może zoptymalizować bezużyteczne polecenia kończące?

27

Jeśli powłoka zostanie poproszona o wykonanie prawdopodobnie bezużytecznej ( lub częściowo bezużytecznej ) komendy, o której wiadomo, że kończy działanie, na przykład cat hugeregularfile.txt > /dev/null, czy może pominąć wykonanie tej komendy ( lub wykonać tańszy odpowiednik, powiedzmy, touch -a hugeregularfile.txt )?

Mówiąc bardziej ogólnie, czy powłoka jest podobna do kompilatorów C pod tym względem, że może wykonywać dowolną transformację w kodzie źródłowym, o ile obserwowane z zewnątrz zachowanie jest tak, jakby maszyna abstrakcyjna go oceniała?

EDYTOWAĆ

Nota Bene: Moje pierwotnie postawione pytanie miało tytuł, w którym zapytano, czy powłoka może wykonywać te optymalizacje, a nie to, czy powinna, a nawet czy istnieją implementacje, które mogą je wykonać. Teoria interesuje mnie bardziej niż praktyka, chociaż obie są mile widziane.

Nie będę istniał Idonotexist
źródło
Nie, powłoka nie jest tak inteligentna jak nowoczesne kompilatory. W rzeczywistości jest to raczej głupie. Nie zoptymalizuje żadnego niepotrzebnego kodu.
devnull
12
Zgadywanie, co jest intencją użytkownika, nie jest czymś, co powłoka powinna zrobić. Użytkownik może próbować zrobić prawie wszystko za pomocą tego polecenia, optymalizacja go byłaby niewłaściwa, nawet gdyby było to możliwe.
Chris Down,
1
Bez względu na to, że jeśli plik był urządzeniem, to catting robi dużą różnicę. Powłoka może dowiedzieć się, że plik jest urządzeniem, ale nie musi być niezawodny.
yo „
3
Kompilatory @StephaneChazelas C nie muszą „pytać o pozwolenie od kogoś”, aby zoptymalizować skompilowane programy; W standardzie C istnieje zasada „ tak, jakby”, która pozwala im to zrobić. Wygląda na to, że standard POSIX ujednolicił przynajmniej jedną powłokę ( pubs.opengroup.org/onlinepubs/009695399/utilities/… ), a także wiele innych narzędzi ( pubs.opengroup.org/onlinepubs/009604499/utilities/wc.html dla wc, na przykład). Ale według mojej najlepszej wiedzy POSIX nie zajmuje stanowiska w sprawie optymalizacji powłoki; A może to?
Nie będę istniał Idonotexist
2
Optymalizacja poprawia wydajność dzięki skrótom bez wpływu na funkcjonalność. Tak długo, jak funkcjonalność jest gwarantowana, nie widzę sprzeciwu POSIX. Proponowana optymalizacja spowodowałaby jednak uszkodzenie specyfikacji cat . W specyfikacji POSIX są określone sformułowania, które mają na celu dostosowanie do typu optymalizacji przeprowadzonej przez ksh. Jakby nie mówili o oddzielnym procesie, ale o środowisku podpowłoki, aby umożliwić optymalizację oszczędzania widelca.
Stéphane Chazelas,

Odpowiedzi:

26

Nie, to byłby zły pomysł.

cat hugeregularfile.txt > /dev/nulli touch -a hugeregularfile.txtnie są takie same. catodczyta cały plik, nawet jeśli przekierujesz wyjście do /dev/null. A odczytanie całego pliku może być dokładnie tym, czego chcesz. Na przykład w celu buforowania, aby późniejsze odczyty były znacznie szybsze. Powłoka nie może poznać twojego zamiaru.

Podobnie, kompilator C nigdy nie zoptymalizuje odczytu pliku, nawet jeśli nie spojrzysz na rzeczy, które czytasz.

scai
źródło
2
@Iwillnotexist: Każde przydatne polecenie (z wyjątkiem prawdopodobnie truei false) ma potencjalne skutki uboczne, a efekty uboczne są prawie zawsze celem wywołania polecenia. Powłoka nie mogła z góry poznać tych skutków ubocznych (dla programów zewnętrznych, takich jak cat) bez rozwiązania problemu zatrzymania. Więc słusznie nie próbuje i zakłada, że ​​miałeś na myśli to, co powiedziałeś.
cHao
5
@IwillnotexistIdonotexist Nie, powłoka nie widzi wszystkiego, co ma się wydarzyć. Nie ma o tym pojęcia cat. W rzeczywistości catmoże zrobić wszystko, od sformatowania dysku twardego do pobierania Internetu.
scai
5
„Uniks nie został zaprojektowany, aby powstrzymywać użytkowników przed robieniem głupich rzeczy, ponieważ powstrzymałoby to ich także od robienia mądrych rzeczy”. - Doug Gwyn
Agi Hammerthief
7
@ cHao A nawet truei falseustaw $?.
Kyle Strand
3
Jak @scai wskazano powyżej, pliki wykonywalne nie są jak słowa kluczowe językowych: cati /dev/nullmają typowe znaczenia, ale nie są one gwarantowane , aby zachowywać się w ten sposób. Aby przeprowadzić optymalizacje, gwarantując bez zmian oczekiwane zachowanie, optymalizacja może być dozwolona tylko przy użyciu konstrukcji zaimplementowanych w samej powłoce, a nie elementów znalezionych w środowisku wykonawczym ... bez względu na to, jak intuicyjnie mogą wyglądać ich nazwy.
andybuckley,
20

Nie, ponieważ /dev/nulljest to tylko nazwa, której można użyć dla dowolnego innego urządzenia lub pliku innego niż „normalnie” ujście danych.

Zatem powłoka (lub jakikolwiek inny program) nie ma pojęcia, na podstawie nazwy, czy plik, do którego pisze, robi coś „naprawdę” z danymi. AFAIK również nie wywołuje żadnych wywołań systemowych, które program powłoki może wykonać, aby ustalić, że np. Deskryptor pliku w rzeczywistości nic nie robi.

Twoje porównanie z optymalizacją kodu wyjściowego w programie C nie działa, ponieważ powłoka nie ma pełnego przeglądu, jaki kompilator C ma nad fragmentem kodu źródłowego. Powłoka nie wie wystarczająco dużo, /dev/nullaby zoptymalizować twój przykład, bardziej jak kompilator C nie wie wystarczająco dużo o kodzie w wywołaniu funkcji, do której dynamicznie się łączy, aby nie wykonać wywołania.

Anthon
źródło
4
Jak się okazuje, ksh93 czasami będzie traktował /dev/nullspecjalnie. Wbudowanym poleceniem, które jego stdout skierowany do /dev/null, na przykład echo foo >/dev/null, nie spowoduje jakichkolwiek zapisów robi się /dev/null. Nie robi nic specjalnego, jeśli wywołuje niewbudowane polecenie (takie jak cat file >/dev/null).
Mark Plotnick,
Faktem catmoże być coś innego. Cokolwiek innego w rzeczywistości.
Orion
3
W rzeczywistości /dev/nulljest jednym z niewielu standardowych ścieżek , wraz z /dev/tty, /dev/console, /tmp, /dev/i /.
Gilles 'SO - przestań być zły'
2
@MarkPlotnick W rzeczywistości cat jest wbudowany w ksh93 (nie jest włączony, chyba że włożysz go /opt/ast/binwcześniej /bin(lub gdziekolwiek catjest dostępny $PATH). I tak, chociaż cat file > /dev/nullz tym wbudowanym robi readzawartość file, nie zapisuje go do / dev / null (chociaż otwiera się i fstats to).
Stéphane Chazelas,
14

Nie zoptymalizuje uruchomionych poleceń (a otrzymałeś już wiele drobnych odpowiedzi, które mówią ci, dlaczego nie powinien), ale może zoptymalizować rozwidlenia, pary rur / gniazd, w niektórych przypadkach czyta. Rodzaj optymalizacji, jakie może on wykonać:

  • W przypadku większości współczesnych powłok ostatnia komenda w skrypcie jest generalnie wykonywana w procesie powłoki, chyba że niektóre trapzostały ustawione. Na przykład, w sh -c ls, większości shimplementacji ( bash, mksh, ksh, zsh, yash, w niektórych wersjach ash) nie rozwidla procesu w celu uruchomienia ls.
  • w ksh93, podstawienie polecenia nie utworzy potoku ani nie rozwidli procesu, dopóki nie zostanie wywołane polecenie zewnętrzne ( $(echo foo)na przykład zostanie rozszerzone foobez pary potoku / gniazda lub rozwidlenia).
  • readwbudowane w niektórych muszli ( bashAT & T ksh) nie zrobi jednobajtowe czyta jeśli wykryje stdin jest możliwy do przeszukania (w takim przypadku będą robić duże czyta i dążyć z powrotem do końca, co oni mają do odczytu).
Stéphane Chazelas
źródło
Podoba mi się ta odpowiedź, ale nie jest jasne, czy jest to pierwotny powód, czy też informacje pochodzą z jakiegoś
źródła
3
@yoniYalovitsky, to oryginalny powód . ksh93jest powłoką wiodącą na froncie optymalizacji, ponieważ jej celem jest / miało być postrzegane jako dorównujące językom programowania takim jak perl. Możesz więc zajrzeć do kshdokumentacji, kodu (powodzenia) i listy mailingowej w celu uzyskania dalszych informacji.
Stéphane Chazelas,
1
@HenkLangeveld, tak, możesz zweryfikować to, sh -c 'ps -p "$$"'co da ci, psa nie za shpomocą tych shimplementacji, lub za pomocą strace / truss / tusc ...
Stéphane Chazelas
1
Różnica między ksh -c 'ps; ps'i bash -c 'ps; ps' jest interesująca. Ksh93 idzie dalej w zakresie optymalizacji.
Henk Langeveld
1
@HenkLangeveld, zależy od tego, o jakiej realizacji kshtutaj mówimy. mkshzachowuje się jak bash. Takie zachowanie ma głównie na celu optymalizację takich rzeczy system("some command"). Zauważ, że efektem ubocznym tej optymalizacji jest status wyjścia procesów zakończonych sygnałem (w niektórych powłokach). ksh93Kiedyś miał błąd polegający na tym, że optymalizował nawet wtedy, gdy ustawiono pułapki.
Stéphane Chazelas
7

Widząc cat hugeregularfile.txt > /dev/null, powłoka nie może uwierzyć, że akcja jest bezużyteczna - catnie jest częścią powłoki i mogłaby w ogóle zrobić wszystko w teorii, a także w praktyce.

Na przykład, użytkownik może mieć przemianowany plik wykonywalny rmdo cati nagle wykonuje linia zewnętrznie obserwowalne zachowanie, czyli usunięcie pliku.

Użytkownik mógł skompilować wersję, catktóra przechodzi w nieskończoną pętlę, więc powłoka nie może zakładać, że „wiadomo, że kończy się”, jak sugerujesz.

Ktoś mógł zainstalować wersję, catktóra działa zgodnie z przeznaczeniem, ale z dodatkowym efektem ubocznym instalowania rootkita, jeśli kiedykolwiek będzie działał z odpowiednimi uprawnieniami - ponownie powłoka powinna go należycie wykonać.

Piotr jest
źródło
2
W mkshrzeczywistości optymalizuje V=$(cat file), czyniąc go wbudowanym. Więc powłoka może ją zoptymalizować, ale nie przekształcić jej w tylko touch -a.
Steve Schnepp,
1
@SteveSchnepp, cat jest wbudowanym poleceniem w mksh, ale to ośrodki wbudowane do systemu cat, jeśli przekazywane żadnej opcji, dlatego z GNU cat, mksh -c 'cat /dev/null --help'nie daje taki sam wynik jak bash -c 'cat /dev/null --help', ale mksh -c 'cat --help /dev/null'nie daje to samo co bash -c 'cat --help /dev/null'(jak mkshkot wbudowanym analizuje możliwości POSIX sposób, podczas gdy kot GNU analizuje je w sposób GNU).
Stéphane Chazelas
W bash i ksh93 V=$(cat file)można to zoptymalizować za pomocą V=$(< file). Przyspiesza to rzeczy nawet bez wbudowanego cat.
Henk Langeveld