Natknąłem się na ten skrypt:
#! /bin/bash
if (( $# < 3 )); then
echo "$0 old_string new_string file [file...]"
exit 0
else
ostr="$1"; shift
nstr="$1"; shift
fi
echo "Replacing \"$ostr\" with \"$nstr\""
for file in $@; do
if [ -f $file ]; then
echo "Working with: $file"
eval "sed 's/"$ostr"/"$nstr"/g' $file" > $file.tmp
mv $file.tmp $file
fi
done
Jakie jest znaczenie linii, w których używają shift
? Zakładam, że skrypt powinien być używany przynajmniej z argumentami, więc ...?
shell-script
arguments
Patryk
źródło
źródło
pushd
ipopd
).bash
, pytanie jest ogólne dla wszystkich powłok, dlatego dominuje standard Posix: pubs.opengroup.org/onlinepubs/9699919799/utilities/…Jak opisano komentarz złotowłosa i odniesienia ludzkości,
shift
ponownie przypisuje parametry pozycyjne ($1
,$2
itp.), Aby$1
nabiera starej wartości$2
,$2
przyjmuje wartość$3
itp. * Stara wartość$1
jest odrzucana. ($0
nie ulega zmianie). Oto niektóre powody:$10
nie działa - jest interpretowane jako$1
połączone z0
(i dlatego może wytworzyć coś takiegoHello0
). Po ashift
następuje dziesiąty argument$9
. (Jednak w większości nowoczesnych powłok możesz użyć${10}
.)for
jest do tego znacznie lepszy.$1
i$2
są ciągami tekstowymi, a$3
wszystkie inne parametry są nazwami plików.Oto jak to się gra. Załóżmy, że twój skrypt jest wywoływany
Patryk_script
i nazywa się jakoSkrypt widzi
Instrukcja
ostr="$1"
ustawia zmiennąostr
naUSSR
. Pierwszashift
instrukcja zmienia parametry pozycyjne w następujący sposób:Instrukcja
nstr="$1"
ustawia zmiennąnstr
naRussia
. Drugashift
instrukcja zmienia parametry pozycyjne w następujący sposób:A następnie
for
zmiany loopUSSR
($ostr
) doRussia
($nstr
) w plikachTreaty1
,Atlas2
orazPravda3
.Istnieje kilka problemów ze skryptem.
Jeśli skrypt zostanie wywołany jako
to widzi
ale, ponieważ
$@
nie jest cytowany, przestrzeń wWorld Atlas2
nie jest cytowany, afor
pętla myśli, że ma cztery pliki:Treaty1
,World
,Atlas2
iPravda3
. Tak powinno być(aby zacytować dowolne znaki specjalne w argumentach) lub po prostu
(co odpowiada dłuższej wersji).
Nie ma takiej potrzeby
eval
, a przekazywanie niepotwierdzonych danych wejściowych do użytkownikaeval
może być niebezpieczne. Na przykład, jeśli skrypt jest wywoływany jakowykona się
rm *
! Jest to duży problem, jeśli skrypt można uruchomić z uprawnieniami wyższymi niż uprawnienia użytkownika, który go wywołuje; np. jeśli można go uruchomićsudo
lub wywołać z interfejsu sieciowego. Prawdopodobnie nie jest to tak ważne, jeśli po prostu używasz go jako siebie, w swoim katalogu. Ale można to zmienić naWciąż wiąże się to z pewnym ryzykiem, ale są one znacznie mniej dotkliwe.
if [ -f $file ]
,> $file.tmp
Imv $file.tmp $file
powinna byćif [ -f "$file" ]
,> "$file.tmp"
imv "$file.tmp" "$file"
, odpowiednio, do obsługi nazw plików, które mogą mieć spacji (lub innych znaków śmieszne) w nich. (eval "sed …
Polecenie zmienia także nazwy plików ze spacjami).*
shift
przyjmuje opcjonalny argument: dodatnia liczba całkowita, która określa liczbę parametrów do przesunięcia. Domyślna wartość to jeden (1
). Na przykładshift 4
powoduje , że$5
się staje$1
,$6
staje się$2
itd. (Zauważ, że przykład w Bash Guide dla początkujących jest błędny.) Tak więc twój skrypt może zostać zmodyfikowany tak, by powiedziałco można uznać za bardziej jasne.
Uwaga końcowa / ostrzeżenie:
Język wiersza poleceń systemu Windows (plik wsadowy) obsługuje także
SHIFT
polecenie, które działa w zasadzie tak samo jakshift
polecenie w powłokach uniksowych, z jedną uderzającą różnicą, którą ukryję, aby zapobiec pomyłkom ludzi:źródło
shift
można zastosować dowhile
,until
a nawet dofor
pętli do obsługi tablic w znacznie bardziej subtelny sposób niż zwykłafor
pętla. Często przydaje mi się wfor
pętlach takich jak ...set -f -- $args; IFS=$split; for arg do set -- $arg; shift "${number_of_fields_to_discard}" && fn_that_wants_split_arg "$arg"; done
Najprostsze wytłumaczenie jest następujące. Rozważ polecenie:
Bez
shift
Twojej pomocy nie możesz wyodrębnić pełnej wartości lokalizacji, ponieważ ta wartość może być dowolnie długa. Po dwukrotnym przesunięciu argumentySET
ilocation
są usuwane w taki sposób, że:Spójrz na to bardzo długo
$@
. Oznacza to, że może zapisać całą lokalizację w zmiennejx
pomimo spacji i przecinków, które ma. Podsumowując, wywołujemy,shift
a następnie pobieramy wartość tego, co zostało ze zmiennej$@
.AKTUALIZACJA Dodaję poniżej bardzo krótki fragment pokazujący koncepcję i przydatność,
shift
bez których bardzo trudno byłoby poprawnie wyodrębnić pola.Objaśnienie : Po
shift
zmiennej zmienna b będzie zawierać resztę przekazywanych elementów, bez względu na spacje itp.[ -n "$b" ] && echo $b
Jest to taka ochrona, że drukujemy b tylko, jeśli ma treść.źródło
"$*"
"$@"
Philippines 6014
), spacji wiodących, spacji końcowych lub tabulatorów. (5) BTW, możesz także być w stanie robić to, co robisz tutaj w bashx="${*:3}"
.shift
poleceniem. Być może odwołujesz się do subtelnych różnic $ @ versus $ *. Ale nadal pozostaje faktem, że mój fragment powyżej może dokładnie wyodrębnić lokalizację bez względu na to, ile spacji ma przed sobą lub z przodu, nie ma to znaczenia. Po zmianie lokalizacja będzie zawierać prawidłową lokalizację.shift
traktuj argumenty wiersza poleceń jako kolejkę FIFO, jest to element przewijany za każdym razem, gdy jest wywoływany.źródło