Як коментар Золотоволоска і посилання людства описують,
shift
перепризначення позиційних параметрів ( $1
, $2
і т.д.) , так що $1
бере на старе значення $2
,
$2
приймає значення $3
, і т.д. *
Старе значення $1
відкидається. ( $0
не змінюється.) Деякі причини цього включають:
- Це дозволяє вам легше отримати доступ до десятого аргументу (якщо такий є).
$10
не працює - інтерпретується як $1
об'єднаний з 0
(і може призвести до подібного Hello0
). Після a shift
стає десятим аргументом $9
. (Однак у більшості сучасних оболонок можна використовувати ${10}
.)
- Як демонструє керівництво Bash для початківців , його можна використовувати для перегляду аргументів. ІМНШО, це незграбно;
for
набагато краще для цього.
- Як і у вашому прикладі сценарію, це легко обробляє всі аргументи однаково, за винятком кількох. Наприклад, в сценарії,
$1
і $2
текстові рядки, в той час як $3
і всі інші параметри є іменами файлів.
Тож ось як це виходить. Припустимо, ваш сценарій називається, Patryk_script
і він називається як
Patryk_script USSR Russia Treaty1 Atlas2 Pravda3
Сценарій бачить
$1 = USSR
$2 = Russia
$3 = Treaty1
$4 = Atlas2
$5 = Pravda3
Оператор ostr="$1"
встановлює змінну ostr
на USSR
. Перше shift
твердження змінює позиційні параметри так:
$1 = Russia
$2 = Treaty1
$3 = Atlas2
$4 = Pravda3
Оператор nstr="$1"
встановлює змінну nstr
на Russia
. Друге shift
твердження змінює позиційні параметри так:
$1 = Treaty1
$2 = Atlas2
$3 = Pravda3
І тоді for
зміни циклу USSR
( $ostr
) в Russia
( $nstr
) в файлах Treaty1
, Atlas2
і Pravda3
.
У сценарію є кілька проблем.
для файлу в $ @; робити
Якщо сценарій викликається як
Patryk_script СРСР Російський договір1 "Світовий атлас2" Правда3
це бачить
$ 1 = СРСР
$ 2 = Росія
$ 3 = Договір1
$ 4 = Всесвітній атлас2
$ 5 = Правда3
але, тому що $@
не котируються, простір в World Atlas2
не котируються, і for
цикл думає , що має чотири файли: Treaty1
, World
, Atlas2
і Pravda3
. Це має бути будь-яке
для файлу у "$ @"; робити
(цитувати будь-які спеціальні символи в аргументах) або просто
для файлу
(що еквівалентно більш тривалої версії).
eval "sed 's /" $ ostr "/" $ nstr "/ g' $ файл"
Не потрібно, щоб це було eval
, і передача неперевіреного вводу користувача на базу eval
може бути небезпечною. Наприклад, якщо сценарій викликається як
Patryk_script "'; rm *;'" Російський договір1 Атлас2 Правда3
це виконає rm *
! Це викликає велике занепокоєння, якщо сценарій можна запускати з привілеями, вищими, ніж користувачі, які його викликають; наприклад, якщо це можна запустити через sudo
веб-інтерфейс або викликати ним. Це, мабуть, не так важливо, якщо ви просто використовуєте його як у своєму каталозі. Але це можна змінити на
sed "s / $ ostr / $ nstr / g" "$ файл"
Це все ще має певні ризики, але вони набагато менш серйозні.
if [ -f $file ]
, > $file.tmp
І mv $file.tmp $file
має бути if [ -f "$file" ]
, > "$file.tmp"
і mv "$file.tmp" "$file"
, відповідно, для обробки імен файлів , які можуть мати прогалини (або інші забавні символи) в них. ( eval "sed …
Команда також манглює імена файлів, у яких є пробіли.)
* shift
приймає необов’язковий аргумент: додатне ціле число, яке вказує, скільки параметрів потрібно змістити. За замовчуванням - один ( 1
). Наприклад, shift 4
причини $5
ставати $1
,
$6
ставати $2
тощо. (Зверніть увагу, що приклад у Посібнику з Bash для початківців невірний.) І тому ваш сценарій можна змінити
ostr="$1"
nstr="$2"
shift 2
що може вважатися більш зрозумілим.
Закінчення Примітка / Попередження:
Мова командного рядка Windows (пакетний файл) також підтримує SHIFT
команду, яка в основному робить те ж саме, що і shift
команда в оболонках Unix, з однією разючою різницею, яку я приховую, щоб спробувати не допустити, щоб люди не плутали її:
- Така команда
SHIFT 4
- це помилка, яка дає повідомлення про помилку "Недійсний параметр для команди SHIFT".
SHIFT /n
, де n
ціле число між 0 і 8, є дійсним - але воно не змінює час . Це зрушує один раз, починаючи з з п - го аргументу. Тому змушує (п’ятий аргумент) стати , і так далі, залишаючи аргументи від 0 до 3.n
SHIFT /4
%5
%4,
%6
%5
pushd
іpopd
).