Jak wyświetlać polecenia w skrypcie powłoki bash, ale nie wykonywać ich?

11

Czy istnieje sposób na uruchomienie skryptu powłoki za pomocą echa poleceń, ale bez ich wykonania?

Załóżmy, że mam skrypt usuwający plik, którego nazwa jest przechowywana w zmiennej:

#!/bin/bash
set -v
FN="filename"
rm -f ${FN}

Dodanie set -vspowoduje wykonanie następujących poleceń przed wykonaniem:

$ ./scr.sh
FN="filename"
rm -f ${FN}

Teraz chcę zobaczyć przepływ tego skryptu bez usuwania pliku. IOW, chcę zapobiec wpływowi na środowisko zewnętrzne i system plików. czy to możliwe?

Mógłbym zawinąć wszystkie polecenia za pomocą echopolecenia, ale jest to męczące dla długiego skryptu.

tak
źródło
Nie jestem ekspertem od skryptów bashowych, ale gdybym napisał to w innym języku programowania, zapisałbym wszystkie polecenia w tablicy. w ten sposób powinno się łatwo zapętlić i wykonać polecenia lub wydrukować.
Hugo der hungrige

Odpowiedzi:

8

Nie ma sposobu, aby przejść przez skrypt, aby zobaczyć, jak zadziałałby bez tego. W twoim przykładzie nie ma ifinstrukcji ani pętli. Ale w prawdziwych skryptach często występuje wiele instrukcji warunkowych. Wybór gałęzi zależy często od tego, co się wydarzyło, gdy powłoka uruchomiła poprzednie polecenie. Jeśli nie uruchomi polecenia, powłoka nie będzie wiedziała, jakie dane wyjściowe by wygenerował lub jaki byłby kod powrotu, od czego może zależeć następna gałąź warunkowa lub instrukcja przypisania.

Jeśli chodzi o to, że chcesz dokładnie zbadać skrypt i wiedzieć, co robi, zanim go uruchomisz, nie jest to zły pomysł. Ale realistycznie, o najlepszym sposobem na to jest po prostu przeglądając plik z lesslub vilub coś podobnego.

Dodany

Jeśli opracowujesz skrypt i chcesz go wykonać po raz pierwszy, testując logikę, ale nie wyrządzając żadnych szkód, jeśli masz błąd, rozwiązaniem, którego często mogę użyć, jest modyfikacja tylko oświadczenia, które mogłyby wyrządzić jakiekolwiek szkody poprzez wklejenie echow przód.

Często działa to w typowych rzeczywistych skryptach, ponieważ (a) generowanie list elementów, które będziesz iterować lub wartość, dla której ustawisz zmienną, może być często wygenerowana bez zmiany systemu plików i (b) zwykle wystarcza Załóżmy, że wykonanie polecenia zakończy się powodzeniem.

Nicole Hamilton
źródło
Dzięki. Zaskoczyłoby mnie, gdyby istniał jakiś sposób, właśnie z tego powodu, o którym wspomniałeś, ale i tak postanowiłem spróbować. Powodem tego jest to, że tworzę skrypt, który przenosi pliki na wiele komputerów w sieci i wykonuje pewne działania na zdalnych hostach. Chciałbym zobaczyć przepływ skryptu przed zatwierdzeniem zmian w systemach plików. Równie żmudne byłoby przeglądanie wszystkich zdalnych komputerów w celu korygowania błędów plików ...
ysap 16.01.2013
1
Dodatek: Aby przejść przez skrypt, możesz uruchomić skrypt, trap read debugktóry wykona odczyt po każdej wykonanej linii, a następnie możesz go przechodzić powoli, naciskając klawisz Enter (jest to przydatne, jeśli masz naprawdę długi skrypt i chcesz przetestować to po raz pierwszy).
netigger 14.04.15
8

Myślę, że będziesz musiał powtórzyć echo - jednak jeśli umieścisz polecenie w zmiennej, możesz go włączyć i wyłączyć. Ponadto polecenie może być funkcją i tak złożoną, jak tylko chcesz.

#!/bin/bash
echo 'Debug'
  D=echo
  :>| testy
  ls -l testy
  $D rm -f testy
  ls -l testy
echo $'\n\nLive'
  D=
  :>| testy
  ls -l testy
  $D rm -f testy
  ls -l testy

!$ > ./conditional.sh
Debug
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy
rm -f testy
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy

Live -rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy ls: cannot access testy: No such file or directory

użytkownik191016
źródło
Wymagałem cudzysłowów w poleceniach echo / not-echo, a następnie musiałem użyć D=evalw części na żywo. Ale miła odpowiedź!
Jasper,
5

Śledzisz przepływ za pomocą opcji -x dla bash, ale to nadal wykonywałoby polecenia.

Najlepsze, co możesz zrobić, to po prostu wysłać echo lub skomentować polecenia, które mają efekty zewnętrzne, takie jak rm. Przynajmniej nie musiałbyś zmieniać każdej linii.

parkydr
źródło
Dzięki. Wspomniałem o tej opcji w moim pytaniu, ale tak naprawdę to nie rozwiązuje mojego problemu.
ysap
Przepraszam, myślałem, że masz na myśli powtarzanie każdej linii, -x zredukuje to do kilku poleceń i wyświetli oceny.
parkydr
4

Nie znam żadnej konkretnej metody suchego uruchamiania, ale możemy zastosować pewne środki ostrożności w celu zrozumienia nieznanego skryptu.

  1. Użyj środowiska chroot, aby uruchomić skrypt debugowania. Będzie działać jako piaskownica i zapewni ochronę przed usunięciem / modyfikacją głównych plików systemowych.
  2. Służy bash -n <script>do sprawdzania składni . Z podręcznika gnu bash https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html

-n Read commands but do not execute them; this may be used to check a script for syntax errors. This option is ignored by interactive shells.

  1. Przeczytaj skrypt przynajmniej raz. Możesz użyć instrukcji echo do debugowania, jak wspomniano w odpowiedzi użytkownika 191016 .
    • Uważaj na podejrzany lub podatny na zagrożenia kod.
    • np. związane z rm, komendami wpływającymi na / dev / sda itp.
  2. Zawsze staraj się uruchamiać skrypty jako zwykły użytkownik, unikaj uruchamiania nieznanych skryptów jako root.
  3. Możesz zdefiniować alias, aby utworzyć komendę, która może modyfikować pliki jako interaktywne na początku skryptu Przykład alias rm="rm -i" alias cp="cp -i" alias mv="mv -i" Dla edytorów strumieniowych takich jak sed sed -i(-i modyfikuje plik w miejscu bez -i, uruchamia na sucho dla sed, sprawdź szczegóły na stronie man) można skopiować pełne polecenie i uruchomić. Tuż przed właściwym poleceniem wyświetli wynik na ekranie, a następnie użyj polecenia, aby poczekać, aż dane wejściowe użytkownika będą kontynuowane. Przykład sed -i <pattern> Zamień na sed <pattern> read -p "Press any key..." sed -i <pattern>

Zawsze zaleca się również zachowanie punktów zapasowych w systemie, aby w razie awarii można było przywrócić dane.

Rohit Raj Mishra
źródło
3

Wykonaj set –nlub dołącz ndo istniejącego set –vpolecenia. Ale ponieważ powoduje to, że powłoka nie ocenia żadnych poleceń, nawet, iflub while, możesz nie uzyskać zbyt dobrego widoku przepływu operacyjnego.

Scott
źródło
Dzięki. To dobry początek, ale jak wspomniałeś, nie pozwala mi zobaczyć rzeczywistego przepływu - gdzie w moim prawdziwym skrypcie mam pętlę nad listą zdalnych hostów.
ysap
3

Oto mały konstrukt, którego lubię używać:

#!/bin/sh

verbose=false
really=true

# parse arguments
while [ $# -ge 1 ]
do
  case "$1" in
    -v) verbose=true ;;
    -n) really=false; verbose=true ;;
  esac
  shift
done

doCmd() {
  if $verbose; then echo "$@"; fi
  if $really; then "$@"; fi
}

doCmd make foo
doCmd rm -rf /tmp/installdir
doCmd mkdir /tmp/installdir
doCmd whatever
doCmd blah blah
Edward Falk
źródło
2

Jeśli chcesz zapobiec wprowadzaniu modyfikacji, możesz uruchomić skrypt jako użytkownik bez uprawnień:

sudo -u nobody ./scr.sh

W twoim przykładzie będzie to działać FN="filename"jak zwykle. Chociaż technicznie wykonuje to polecenie rm -f ${FN}, nic się nie stanie, jeśli nikt nie będzie miał niezbędnych uprawnień do usunięcia pliku.

Oczywiście spowoduje to problemy z warunkowym przepływem pracy. Fakt, że rmpolecenie nie powiodło się, może wpłynąć na dalsze części skryptu.

Dennis
źródło
Rzeczy, których nigdy nie zrozumiemy: Dlaczego root musi działać jako nikt ...
mjohnsonengr
Użytkownik „nobody” nie jest spevialny w systemie operacyjnym, ale możesz dodać wpis w pliku sudoers, który zezwala na sudo bez hasła dla „nobody”.
Dennis,
Nie wiem. Wydaje się, że skrypt zakończyłby się z powodu jakiegoś błędu lub innego przed zakończeniem.
Edward Falk,