Jak działa ten złożony skrypt powłoki BASH?

4

Członek społeczności Apple Support, Linc Davis, opracował to polecenie, aby pomóc w diagnozowaniu problemów. Dane wyjściowe dają ogólny przegląd własnego systemu i są bardzo podobne do etrecheck programu . Ale robi to za pomocą jednego polecenia. Chciałbym opisać, jak to działa, ponieważ znacznej części użytej składni nie można znaleźć na stronach MAN. Ponownie ten skrypt jest własnością Linc Davis. Chcę po prostu zrozumieć, jak to działa. Z góry dziękuję.

clear; shopt -s extglob; Fb='%s\n\t(%s)\n'; Fm='\n%s:\n\n%s\n'; Fs='\n%s: %s\n'; PB="/usr/libexec/PlistBuddy -c Print"; Pm () { [[ "$o" ]] && o=$(sed 's/^/ /' <<< "$o") && printf "$Fm" "$1" "$o"; }; Pc () { o=$(egrep -v '^[[:blank:]]*($|#)' "$2"); Pm "$1"; }; Pp () { o=$($PB "$2" | awk -F'= ' \/$3'/{print $2}'); Pm "$1"; }; Ps () { o="${o##+( )}"; [[ "$o" -ne 0 ]] && printf "$Fs" "$1" "$o"; }; a=$(id | grep -w '80(admin)'); r=1; [[ "$a" ]] && { sudo true; r=$?; }; { [[ "$a" ]] || echo $'No admin access\n'; [[ "$a" && "$r" -ne 0 ]] && echo $'No root access\n'; system_profiler SPSoftwareDataType | sed '8!d;s/^ *//'; o=$(system_profiler SPDiagnosticsDataType | sed '5,6!d'); fgrep -q P <<< "$o" && o=; Pm "POST"; o=$(nvram boot-args | awk '{$1=""; print}'); Ps "boot-args"; o=$(df -m / | awk 'NR==2 {print $4}'); [[ $o -lt 5120 ]] && Ps "Free space (MiB)"; o=$(($(vm_stat | awk '/Pageo/{sub("\\.",""); print $2}')/256)); o=$((o>=1024?o:0)); Ps "Pageouts (MiB)"; s=( $(sar -u 1 10 | sed '$!d') ); [[ ${s[4]} -lt 90 ]] && o=$(printf 'User %s%%\t\tSystem %s%%' ${s[1]} ${s[3]}) || o=; Pm "Total CPU usage" && o=$(ps acrx -o comm,ruid,%cpu | sed '2!d'); Pm "Max %CPU by process (name, UID, %)"; o=$(kextstat -kl | grep -v com\\.apple | cut -c53- | cut -d\< -f1); Pm "Loaded extrinsic kernel extensions"; o=$(launchctl list | sed 1d | awk '!/0x|com\.apple|org\.(x|openbsd)|\.[0-9]+$/{print $3}'); Pm "Loaded extrinsic user agents"; o=$(launchctl getenv DYLD_INSERT_LIBRARIES); Pm "Inserted libraries"; for f in crontab fstab launchd.conf sysctl.conf; do Pc $f /etc/$f; done; Pc "hosts" <(sed '1,10d' /etc/hosts); Pc "User crontab" <(crontab -l); Pc "User launchd" ~/.launchd; o=$(find {,/u*/lo*}/e*/periodic -type f -mtime -10d); Pm "Modified periodic scripts"; Pp "Global login items" /L*/P*/loginw* Path; Pp "User login items" L*/P*/*loginit* Name; Pp "Safari extensions" L*/Saf*/*/E*.plist Bundle | sed 's/\..*$//;s/-[1-9]$//'; o=$(find ~ $TMPDIR.. \( -flags +sappnd,schg,uappnd,uchg -o ! -user $UID -o ! -perm -600 \) | wc -l); Ps "Restricted user files"; cd; o=$(find -L /S*/L*/E* {/,}L*/{A*d,Compon,Ex,In,Keyb,Mail/Bu,P*P,Qu,Scripti,Servi,Spo}* -type d -name Contents -prune | while read d; do ID=$($PB\ :CFBundleIdentifier "$d/Info.plist") || ID="No bundle ID"; egrep -qv "^com\.apple\.[^x]|Accusys|ArcMSR|ATTO|HDPro|HighPoint|driver\.stex|hp-fax|\.hpio|JMicron|microsoft\.MDI|print|SoftRAID" <<< $ID && printf "$Fb" "${d%/Contents}" "$ID"; done); Pm "Extrinsic loadable bundles"; o=$(find /u*/{,*/}lib -type f -exec sh -c 'file -b "$1" | grep -qw shared && ! codesign -v "$1"' {} {} \; -print); Pm "Unsigned shared libraries"; o=$(system_profiler SPFontsDataType | egrep "Valid: N|Duplicate: Y" | wc -l); Ps "Font problems"; for d in {/,}L*/{La,Priv,Sta}*; do o=$(ls -A "$d" | egrep -v '\.DS_Store|^com\.apple'); Pm "$d"; done; o=$(ls /L*/L*/Dia*/*.panic | wc -l); Ps "Panics"; o=$(ls /L*/L*/Dia*/*.c* | tail); Pm "System crash logs"; o=$(ls L*/L*/Dia* | tail); Pm "User crash logs"; [[ "$r" -eq 0 ]] && { o=$(sudo profiles -P); Pm "Profiles"; o=$(sudo launchctl list | sed 1d | awk '!/0x|com\.(apple|openssh|vix\.cron)|org\.(amav|apac|calendarse|cups|dove|isc|ntp|post[fg]|x)/{print $3}'); Pm "Loaded extrinsic daemons"; o=$(sudo defaults read com.apple.loginwindow LoginHook); Pm "Login hook"; Pc "Root crontab" <(sudo crontab -l);}; o=$(syslog -F bsd -k Sender kernel -k Message CReq 'GPU |hfs: Ru|I/O e|n Cause: -|NVDA\(|pagin|timed? ?o' | tail -n25 | awk '/:/{$4=""; $5=""; print}'); Pm "Kernel messages"; } 2> /dev/null | pbcopy; exit

njboot
źródło

Odpowiedzi:

5

Pierwszą rzeczą do zrozumienia jest to, że tak naprawdę nie jest to „pojedyncze polecenie”, jest to pojedyncza linia tylko dlatego, że używa „;” do oddzielania linii poleceń zamiast nowych linii.

Pierwszą rzeczą, którą należy zrobić, próbując zrozumieć, jest uczynienie go bardziej czytelnym dla człowieka, używając ulubionego edytora tekstu do zastąpienia „;” z nową linią. Użyłem Textmate i zapisałem wynik jako „linc.sh”, więc dostałem podświetlanie składni. Potem kilka rozsądnych przeformatowań / ładnych i miałem to:

wprowadź opis zdjęcia tutaj

Gdy to zrobisz, będziesz mieć skrypt powłoki i zobaczysz, że używa zmiennych powłoki i rozszerzenia do budowania opcji przed uruchomieniem polecenia, a następnie używania poleceń grep, awk i sed do przetworzenia danych wyjściowych i uczynienia go bardziej czytelnym przed powtórzeniem cała sprawa z innym poleceniem. Jest tam również kilka funkcji powłoki.

Zdobądź dobrą książkę na temat programowania bash, a dzięki pomocy i stronom podręcznika bash zrozumiesz.

(BTW - jest to jeden z powodów, dla których tak samo administruję systemem w IPython, znacznie ułatwia programowanie i czytelny kod.)

Tony Williams
źródło
Dziękuję Tony, to jest bardzo pomocna informacja. Mówiąc dokładniej, na przykład „Fb / Fm / Fs”, gdzie znajdę dokumentację na ten temat? Czy te zmienne? Niedawno kupiłem O'Reilly: „Shell Scripting” i jeszcze nie zagłębiłem się w to, ale planuję wkrótce. Dzięki jeszcze raz.
njboot
1
Tak, są to zmienne powłoki. Przeczytaj książkę O'Reilly od deski do deski i jestem pewien, że zaczniesz wszystko rozumieć. Programowanie powłoki na tym poziomie nie jest łatwe. Dzieje się tam wiele głębokich rzeczy.
Tony Williams