Shift bash что это
На операционных системах семейства Unix (Linux, FreeBSD и т. п.) в скриптах шелла bash работает команда shift. Когда она выполняется, происходит сдвиг влево позициональных параметров скрипта (т. е. аргументов командной строки, переданных в скрипт). Каждый из параметров помещается в более младшую относительно текущей позицию.
[Описание команды shift]
Когда вы запускаете shift n , текущие позициональные параметры сдвигаются влево n раз. Позициональный параметр x получает значение позиционального параметра x+n. Если параметр x+n не существует, то параметр x становится неустановленным.
Если величина сдвига n для команды shift не указана, то применяется значение по умолчанию 1. Таким образом, команды shift 1 и shift без аргумента делают одно и то же.
Если параметр сдвигается в позицию, которая меньше 1, то он выбрасывается, т. е. его значение теряется. Так что, к примеру, команда shift будет всегда выбрасывать предыдущее значение $1, и shift 2 всегда выбросит предыдущие значения $1 и $2.
Специальный позициональный параметр $0 исключается из операций shift, и он всегда остается доступным, на него команда shift не влияет.
Синтаксис команды shift:
Параметры. Команда shift принимает только 1 аргумент:
| n | Количество позиций, на которое параметры должны быть сдвинуты влево. Это значение может быть любым неотрицательным целым числом. Если для n указан ноль (0), то никакой сдвиг параметров не производится. Значение по умолчанию для n (если параметр n не указан) равно 1. |
n Количество позиций, на которое параметры должны быть сдвинуты влево. Это значение может быть любым не отрицательным целым числом. Если для n указан ноль (0), то никакой сдвиг параметров не производится. Значение по умолчанию для n (если параметр n не указан) равно 1.
Возвращаемый статус: при успешном завершении команды shift она возвратит значение 0 (что соответствует отсутствию ошибок). В противном случае, если n отрицательное, или n больше, чем текущее количество позициональных параметров, то будет возвращено ненулевое значение.
При исполнении команды Linux (в том числе скрипта bash) в её переменные окружения добавляются параметры командной строки, которые были указаны при запуске скрипта. Имя этих специальных переменных состоят из символа $ и цифры, значение которых соответствует позиции параметра в командной строке (поэтому параметры называют позициональными).
Для примера рассмотрим команду:
У этой команды есть 3 позициональных параметра $0, $1 и $2:
| Параметр | Позиция | Описание |
| mv | 0 | Сама команда mv, которая перемещает файлы. В этом примере команда переименовывает файл file_old.txt в файл file_new.txt. |
| file_old.txt | 1 | Оригинальное имя файла. |
| file_new.txt | 2 | Новое имя файла. |
Первый параметр 0 содержит имя команды. Если для команды не было предоставлено аргументов, то это будет единственный позициональный параметр.
Когда для команды были указаны параметры, каждый из них сохраняется в массив строк с позициональными индексами 1, 2, и т. д. В скрипте к этим переменным можно получить значение по имени, составленному из символа доллара $ и значения индекса параметра (1, 2, и т. д.). Таким образом, значение позиционального параметра 1 доступно через значение переменной $1, значение параметра 2 можно получить из переменной $2, и т. д.
К параметрам с числом 10 или больше можно обратиться, заключив число в фигурные скобки, например $<10>, $<11>, или $<12345>.
Bash отслеживает общее количество позициональных параметров. Это количество сохраняется в специальной переменной окружения $# .
Каждый раз при выполнении команды shift значение $# уменьшается на n (n параметр команды shift или 1, если команда shift запущена без параметров).
Специальный позициональный параметр 0. Этот параметр содержит имя команды, которая была использована для запуска текущего процесса. Таким образом, вы всегда можете узнать через этот параметр имя запущенной команды.
Например, в приглашении команд шелла bash вы можете запустить echo $0 , чтобы увидеть команду, которая была запущена в текущей сессии bash:
Результат команды echo $0 показывает место расположения исполняемого файла bash.
Есть несколько способов запустить выполняемый файл. Однако следует иметь в виду, что многие программы запускаются через псевдонимы symlink (символическая ссылка, symbolic link). Если вы запустите команду с использованием symlink, то $0 будет содержать имя используемой ссылки.
Например, вы можете создать символическую ссылку на bash в своей домашней директории
После этого сделайте symlink выполняемой с помощью команды chmod :
Затем вы можете запустить новый дочерний процесс bash выполнением symlink:
Запустится новая командная строка шелла bash, внутри предыдущего шелла. Если вы теперь запустите echo $0 , то увидите разницу:
Эта команда показала полный путь до запущенной команды, в котором псевдоним
(тильда) в пути был развернут до реального, начинающегося от корня системы / . Если теперь выполнить команду exit , то произойдет возврат в ваш изначальный шелл.
Примечание: для программы, написанной на языке C, к позициональным параметрам обращаются через параметры argc и argv, где argv это массив указателей на строки, а argc это целое число, равное количеству элементов в массиве. Значение argc всегда больше или равно 1, и значение argv[0] всегда соответствует позициональному параметру $0, т. е. имени запущенной команды.
[Примеры команды shift]
Создадим простой скрипт, который принимает аргументы. Так мы на практике увидим, как аргументы сохраняются в окружении в виде позициональных параметров, и как shift на них влияет. Для создания скрипта используйте любой редактор, например vim , gedit или mcedit , после чего с помощью команды chmod u+x имяскрипта поменяйте его атрибуты, разрещающие запуск.
Первая строка скрипта содержит «магическую» строчку #!/bin/bash , которая определяет интерпретатор скрипта (программу шелла), который должен быть использован для обработки команд скрипта.
Вторая строка shift 0 пока ничего не делает. Позже мы поменяем 0 на другое значение, чтобы понять, как работает команда shift.
Предположим, что мы создали новый файл скрипта с именем myargs.sh. Сделаем его исполняемым:
После этого запустим, указав для него пять аргументов:
В этом выводе видны значения позициональных параметров 0 .. 4. Значение параметра $5 равно «five», однако в скрипте оно не используется.
Указанные в команде параметры относятся только к текущей запускаемой команде — нашему скрипту myargs.sh. После завершения команды (скрипта) они теряются, вернее откатываются к своему изначальному (в нашем примере пустому) значению, которое было до запуска команды. Вы можете запустить команду:
Здесь отображены значение переменных вашей текущей сессии bash. $0 это место размещения исполняемого кода bash, а у остальных параметров $1 .. $4 значения отсутствуют.
Давайте теперь поменяем shift 0 на shift 1:
Примечание: все, что указано после символа «#», считается комментарием, и игнорируется при запуске скрипта.
Теперь при запуске той же самой команды мы увидим следующее:
Обратите внимание, что позиция всех параметров была сдвинута на 1. Оригинальное значение $1 было выброшено, и значение $5 теперь стало значением $4. Значение $0 не поменялось.
Однако простой сдвиг на единицу не особо полезен. Обычно shift запускают несколько раз в цикле, что удобно для выполнения одинаковых повторяющихся действий над параметрами (мы это рассмотрим далее на практическом примере). Для цикла скрипт можно переписать следующим образом:
Обратите внимание, что здесь shift это последняя команда в теле цикла. Это позволяет выполнить какую-либо обработку со всеми начальными параметрами до того, как будет произведен самый первый сдвиг.
Запустим наш скрипт снова. Он прокрутится 5 раз (i будет последовательно увеличиваться от 0 до 4). С каждой итерацией тела цикла shift будет делать сдвиг позициональных параметров влево, с выводом в терминал значений переменных $1 .. $4.
Практический пример использования shift. Следующий скрипт clean-old-files.sh принимает в командной строке список имен директорий. Он сканирует каждую из них, проверяя дату модификации находящихся там файлов. Если к каким-либо файлам не было обращения больше одного года, то они удаляются.
Давайте рассмотрим части этого скрипта, чтобы понять, что они делают.
В этом операторе проверки условия if скрипт проверяет, указаны ли какие-либо аргументы. Проверка использует нотацию одиночных скобок [ . ], что эквивалентно встроенной команде test . Специальная переменная окружения $# содержит общее количество позициональных параметров. Если её значение равно 0, то это значит, что пользователь не предоставил для скрипта ни одной директории, в этом случае будет выведен текст подсказки, и скрипт возвратит результат ошибки (exit-статус 1).
Иначе запустится цикл while/do, в его условии применяется проверка условия с двойными круглыми скобками, чтобы проверить, соответствует ли $# значение true (это любое значение, не равне 0). Каждый раз перед запуском прокрутки тела цикла, если $# равно 0, то выражение (( «$#» )) будет вычислено как false, и произойдет выход из цикла.
Примечание: выражения (( «$#» )) и [ «$#» != «0» ] дают одинаковые результаты, и функционально взаимозаменяемые.
Рассмотрим теперь внутренний цикл while:
Эта строка говорит следующее: выполнять, пока (while) имеются раздельные читаемые элементы (-d), отделенные друг от друга нулевым символом ( $’\0′ ), с чтением такого элемента в переменную file, после чего выполнить команды внутри цикла (do).
Элементы предоставляются строкой в теле цикла:
Эта строка говорит: найти все файлы, начинать искать в директории dir1 (позициональный параметр $1), к которой был доступ последний раз (-atime) больше чем ( + ) 365 дней тому назад. Разделить список найденных файлов нулевыми символами null (-print0).
Команда поиска find обернута в <( . ), что использует перенаправление, обрабатывающее вывод как если бы это был файл. Содержимое «файла» перенаправляется ( < ) во внутренний цикл while. Здесь read интерпретирует все до null-символа как имя следующего файла, и назначает это имя переменной file. Затем выполняется тело внутреннего цикла, которое печатает имя удаляемого файла и удаляет его:
Внутренний цикл продолжается до тех пор, пока имена файлов не закончаться, тогда read вернет false. Произойдет выход из внутреннего цикла, где выполняется:
Команда shift сдвинет позициональные параметры, так что dir2 ($2) станет теперь dir1 ($1). Старое значение $1 при сдвиге выбрасывается, и значение $# автоматически декрементируется на 1.
Оператор done делает возврат к началу внешнего цикла while. Если больше позициональных параметров нет, то проверка (( «$#» )) вернет false, произойдет выход из внешнего цикла, и выполнится:
Скрипт завершится успешно (exit-статус 0) с выводом сообщения «Done».
Запуск скрипта может выглядеть следующим образом:
См. также команду getopts — парсинг аргументов, переданных в скрипт шелла [2].
Bash shift builtin command
On Unix-like operating systems, shift is a builtin command of the Bash shell. When executed, it shifts the positional parameters (such as arguments passed to a bash script) to the left, putting each parameter in a lower position.
Description
When you run shift, the current positional parameters are shifted left n times. Positional parameter x is given the value of parameter x+n. If parameter x+n does not exist, parameter x is unset.
If not specified, the default value of n is 1. So the commands "shift 1" and "shift" (with no argument) do the same thing.
If a parameter is shifted to a position with a number less than 1, it "falls off" — its value is discarded. So the command shift always discards the previous value of $1, and shift 2 always discards the previous values of $1 and $2.
The special positional parameter $0 is excluded from all shift operations, and never modified by the shift command.
Syntax
The shift command takes only one argument:
| n | The number of positions that parameters should be shifted to the left. This value can be any non-negative integer. If n is zero (0), no parameter shift will be performed. The default value of n is 1. |
Exit status
When shift exits, it returns an exit status of 0 (no error), unless: n is negative, or n is greater than the current number of positional parameters, in which case exit status is nonzero.
Positional parameters in bash
In bash, whenever a command is executed, the environment for that command includes special variables containing the individual parameters given to the command.
The name of these variables is a number, corresponding to the position of that parameter on the command line.
For instance, consider the following command:
This command has three positional parameters, numbered as follows:
| Parameter | Position | Description |
|---|---|---|
| mv | 0 | The mv command, which moves files. In this case, it renames file_old.txt to file_new.txt by "moving" it to the new file name. |
| file_old.txt | 1 | The original file name. |
| file_new.txt | 2 | The new file name. |
The first parameter, 0, contains the name of the command. If there are no arguments, this will be the only positional parameter.
When arguments are included after a command, each is stored in the shell variables named 1, 2, etc. Like any other shell variables, their value can be referenced by putting a dollar sign before the variable name. So the value of positional parameter 1 can be referenced with $1, the value of parameter 2 can be referenced with $2, etc.
Parameters with a number 10 or greater can be referenced by putting the number in brackets, for example $ , $ , or $ .
Bash keeps track of the total number of positional parameters. This number is stored in the special shell variable $#.
The value of $# decreases by n every time you run shift.
Special positional parameter zero
Positional parameter zero (0) contains the name of the command that was used to start the current process, as it was executed. You can always find out what command was used to launch the current process by checking the value of this variable.
For instance: from a bash prompt, you can run echo $0 to see the command that launched your current bash session:
This is the location of the bash executable.
There are different ways to run an executable file, however — for instance, many programs are executed using a symlink (symbolic link). If you run a command using a symlink, $0 contains the name of the link you used.
For instance, you can create a symlink to bash in your home directory:
And make the symlink executable, using chmod:
Then, you can start a new bash child process by executing the symlink:
You're now in a new bash shell, inside your previous shell. If you run echo $0, you'll see the difference:
This is the complete path to your home directory, as expanded by bash when you used the alias
(a tilde). You can type exit now, to return to your original bash shell.
Examples
Shifting parameters
Let's create a script that accepts arguments. We'll look at how arguments are stored in the environment as positional parameters, and how shift affects them.
Create a new script with your favorite text editor, such as pico or vim. The script should look like this:
The first line, which begins with #! (a "shebang") defines which shell program should be used to run the script.
The second line ("shift 0") does nothing — yet. After we run the script like this, we'll change 0 to another number.
Now, save this to a file called myargs.sh, and exit the text editor.
Make myargs.sh executable:
Then run it, and give it some arguments:
In this output, we can see the values of positional parameters 0–4. (The value of $5 is "five", but we aren't using that value in our script.)
These values are specific to our current command — the script. When the script is done, these values revert to their values before the script was run. So now, at the command prompt, you can run:
These are the values for our bash session. $0 is the location of the bash executable, and the other parameters have no value.
Now let's change shift 0 to shift 1. Open the script in your text editor and change the second line so the script looks like this:
Everything after the hash mark ("#") on line 2 is a comment, and is ignored when the script runs.
Save the file and exit the text editor. Then, run the script again:
Notice that the position of all the parameters are shifted down by one. The original value of $1 was discarded, and the value of $5 is now at $4. The value of $0 has not changed.
But, running shift only once isn't very useful. Usually, you will want to run it several times, in a loop. We can re-write the above script as a loop, where each iteration shifts the parameters once. In your text editor, change the script to look like this:
Notice that shift is the last command in the loop. This allows us to do something to the parameters before they are shifted. Then, as a final step, we shift the parameters and run the loop again.
Save your changes, exit the text editor, and run the script. It will loop five times (with i incrementing from 0 to 4, once per loop). Each loop will shift the values once, and echo the values 0–4 to the terminal.
Now that we've seen how parameters are shifted, let's create a script with a practical purpose.
Real-world example
The following script, clean-old-files.sh, accepts a list of directory names as parameters on the command line. It scans each named directory for any files that haven't been accessed in more than a year, and deletes them.
Let's look at the individual parts of this script, and analyze what they do:
In this if conditional statement, the script checks if there are any arguments. The test uses single-bracket notation ( [ … ] ), which is equivalent to using the builtin command test. The special shell variable $# holds the total number of positional parameters. If its value is equal to zero, that means the user didn't provide any directory names, so we echo a help message and terminate the script with an error (exit status 1).
Otherwise, we proceed to the outer while loop, which uses double-parentheses evaluation to see if $# is true — that is, if its value is anything other than zero. Every time the loop starts, if $# is zero, the expression evaluates as false and the loop exits.
The expressions (( "$#" )) and [ "$#" != "0" ] give equivalent results, and are functionally interchangeable.
Next, let's look at both sides of the inner while loop:
This line says: while there are read items that are delimited ( -d ) by a null character ( $'\0' ), read one item into the variable file, then perform the commands inside the loop.
The items are provided by the line at the end of the loop:
This line says: find all files, beginning the search in the directory dir1 (in positional parameter $1), that were last accessed (-atime) more than ( + ) 365 days ago. Delimit the list of matching file names with null characters (-print0).
The find command is enclosed in <( … ), which uses process substitution to treat the output as if it's a file. The contents of this "file" are redirected ( < ) to the inner while loop. There, read interprets everything up to a null character as the next file name, and assigns this name to the variable file. Then, the inside of the loop is executed:
Which prints the file name and removes the file.
The inner loop continues until there are no more file names, so read returns false. The inner loop exits to the outer loop, where, we.
shift the positional parameters, so that dir2 ($2) is now dir1 ($1). The old $1 is discarded, and $# is automatically decremented by 1.
Go back to the beginning of the outer while loop. If there are no more positional parameters, the test (( "$#" )) returns false, the outer loop exits, and.
What is the purpose of using shift in shell scripts?
What is the meaning of the lines where they use shift ? I presume the script should be used with at least arguments so.
![]()
4 Answers 4
shift is a bash built-in which kind of removes arguments from the beginning of the argument list. Given that the 3 arguments provided to the script are available in $1 , $2 , $3 , then a call to shift will make $2 the new $1 . A shift 2 will shift by two making new $1 the old $3 . For more information, see here:
![]()
As goldilocks’ comment and humanity’s references describe, shift reassigns the positional parameters ( $1 , $2 , etc.) so that $1 takes on the old value of $2 , $2 takes on the value of $3 , etc. * The old value of $1 is discarded. ( $0 is not changed.) Some reasons for doing this include:
- It lets you access the tenth argument (if there is one) more easily. $10 doesn’t work – it’s interpreted as $1 concatenated with a 0 (and so might produce something like Hello0 ). After a shift , the tenth argument becomes $9 . (However, in most modern shells, you can use $ <10>.)
- As the Bash Guide for Beginners demonstrates, it can be used to loop through the arguments. IMNSHO, this is clumsy; for is much better for that.
- As in your example script, it makes it easy to process all of the arguments the same way except for a few. For example, in your script, $1 and $2 are text strings, while $3 and all other parameters are file names.
So here’s how it plays out. Suppose your script is called Patryk_script and it is called as
The script sees
The statement ostr=»$1″ sets variable ostr to USSR . The first shift statement changes the positional parameters as follows:
The statement nstr=»$1″ sets variable nstr to Russia . The second shift statement changes the positional parameters as follows:
And then the for loop changes USSR ( $ostr ) to Russia ( $nstr ) in the files Treaty1 , Atlas2 , and Pravda3 .
There are a few problems with the script.
If the script is invoked as
but, because $@ isn’t quoted, the space in World Atlas2 isn’t quoted, and the for loop thinks it has four files: Treaty1 , World , Atlas2 , and Pravda3 . This should be either
(to quote any special characters in the arguments) or simply
(which is equivalent to the longer version).
There’s no need for this to be an eval , and passing unchecked user input to an eval can be dangerous. For example, if the script is invoked as
it will execute rm * ! This is a big concern if the script can be run with privileges higher than those of the user who invokes it; e.g., if it can be run via sudo or invoked from a web interface. It’s probably not so important if you just use it as yourself, in your directory. But it can be changed to
This still has some risks, but they are much less severe.
if [ -f $file ] , > $file.tmp and mv $file.tmp $file should be if [ -f «$file» ] , > «$file.tmp» and mv «$file.tmp» «$file» , respectively, to handle file names that might have spaces (or other funny characters) in them. (The eval «sed … command also mangles file names that have spaces in them.)
* shift takes an optional argument: a positive integer that specifies how many parameters to shift. The default is one ( 1 ). For example, shift 4 causes $5 to become $1 , $6 to become $2 , and so on. (Note that the example in the Bash Guide for Beginners is wrong.) And so your script could be modified to say
which might be considered to be more clear.
End Note / Warning:
The Windows Command Prompt (batch file) language also supports a SHIFT command, which does basically the same thing as the shift command in Unix shells, with one striking difference, which I’ll hide to try to prevent people from being confused by it:
Bash-скрипты, часть 3: параметры и ключи командной строки
Освоив предыдущие части этой серии материалов, вы узнали о том, что такое bash-скрипты, как их писать, как управлять потоком выполнения программы, как работать с файлами. Сегодня мы поговорим о том, как добавить скриптам интерактивности, оснастив их возможностями по получению данных от пользователя и по обработке этих данных.

Наиболее распространённый способ передачи данных сценариям заключается в использовании параметров командной строки. Вызвав сценарий с параметрами, мы передаём ему некую информацию, с которой он может работать. Выглядит это так:
В данном примере сценарию передано два параметра — «10» и «20». Всё это хорошо, но как прочесть данные в скрипте?
Чтение параметров командной строки
Оболочка bash назначает специальным переменным, называемым позиционными параметрами, введённые при вызове скрипта параметры командной строки:
- $0 — имя скрипта.
- $1 — первый параметр.
- $2 — второй параметр — и так далее, вплоть до переменной $9 , в которую попадает девятый параметр.
Запустим сценарий с параметрами:
Вот что он выведет в консоль.

Вывод параметров, с которыми запущен скрипт
Обратите внимание на то, что параметры командной строки разделяются пробелами.
Взглянем на ещё один пример использования параметров. Тут мы найдём сумму чисел, переданных сценарию:
Запустим скрипт и проверим результат вычислений.

Сценарий, который находит сумму переданных ему чисел
Параметры командной строки не обязательно должны быть числами. Сценариям можно передавать и строки. Например, вот скрипт, работающий со строкой:
Он выведет то, что мы от него ожидаем.

Сценарий, работающий со строковым параметром
Что если параметр содержит пробелы, а нам надо обрабатывать его как самостоятельный фрагмент данных? Полагаем, если вы освоили предыдущие части этого руководства, ответ вы уже знаете. Заключается он в использовании кавычек.
Если скрипту надо больше девяти параметров, при обращении к ним номер в имени переменной надо заключать в фигурные скобки, например так:
Проверка параметров
Если скрипт вызван без параметров, но для нормальной работы кода предполагается их наличие, возникнет ошибка. Поэтому рекомендуется всегда проверять наличие параметров, переданных сценарию при вызове. Например, это можно организовать так:
Вызовем скрипт сначала с параметром, а потом без параметров.

Вызов скрипта, проверяющего наличие параметров командной строки
Подсчёт параметров
В скрипте можно подсчитать количество переданных ему параметров. Оболочка bash предоставляет для этого специальную переменную. А именно, переменная $# содержит количество параметров, переданных сценарию при вызове.
В результате скрипт сообщит о том, что ему передано 5 параметров.

Подсчёт количества параметров в скрипте
Эта переменная даёт необычный способ получения последнего из переданных скрипту параметров, не требующий знания их количества. Вот как это выглядит:
Вызовем скрипт и посмотрим, что он выведет.

Обращение к последнему параметру
Захват всех параметров командной строки
В некоторых случаях нужно захватить все параметры, переданные скрипту. Для этого можно воспользоваться переменными $* и $@ . Обе они содержат все параметры командной строки, что делает возможным доступ к тому, что передано сценарию, без использования позиционных параметров.
Переменная $* содержит все параметры, введённые в командной строке, в виде единого «слова».
В переменной $@ параметры разбиты на отдельные «слова». Эти параметры можно перебирать в циклах.
Рассмотрим разницу между этими переменными на примерах. Сначала взглянем на их содержимое:
Вот вывод скрипта.

Переменные $* и $@
Как видно, при выводе обеих переменных получается одно и то же. Теперь попробуем пройтись по содержимому этих переменных в циклах для того, чтобы увидеть разницу между ними:
Взгляните на то, что скрипт вывел в консоль. Разница между переменными вполне очевидна.

Разбор переменных $* и $@ в цикле
Переменная $* содержит все переданные скрипту параметры как единый фрагмент данных, в то время как в переменной $@ они представлены самостоятельными значениями. Какой именно переменной воспользоваться — зависит от того, что именно нужно в конкретном сценарии.
Команда shift
Использовать команду shift в bash-скриптах следует с осторожностью, так как она, в прямом смысле слова, сдвигает значения позиционных параметров.
Когда вы используете эту команду, она, по умолчанию, сдвигает значения позиционных параметров влево. Например, значение переменной $3 становится значением переменной $2 , значение $2 переходит в $1 , а то, что было до этого в $1, теряется. Обратите внимание на то, что при этом значение переменной $0 , содержащей имя скрипта, не меняется.
Воспользовавшись командой shift , рассмотрим ещё один способ перебора переданных скрипту параметров:
Скрипт задействует цикл while , проверяя длину значения первого параметра. Когда длина станет равна нулю, происходит выход из цикла. После проверки первого параметра и вывода его на экран, вызывается команда shift , которая сдвигает значения параметров на одну позицию.

Использование команды shift для перебора параметров
Используя команду shift , помните о том, что при каждом её вызове значение переменной $1 безвозвратно теряется.
Ключи командной строки
Ключи командной строки обычно выглядят как буквы, перед которыми ставится тире. Они служат для управления сценариями. Рассмотрим такой пример:
И проанализируем то, что он выведет в терминал.

Обработка ключей в скрипте
В этом коде использована конструкция case , которая сверяет переданный ей ключ со списком обрабатываемых скриптом ключей. Если переданное значение нашлось в этом списке, выполняется соответствующая ветвь кода. Если при вызове скрипта будет использован любой ключ, обработка которого не предусмотрена, будет исполнена ветвь «*».
Как различать ключи и параметры
Часто при написании bash-скриптов возникает ситуация, когда надо использовать и параметры командной строки, и ключи. Стандартный способ это сделать заключается в применении специальной последовательности символов, которая сообщает скрипту о том, когда заканчиваются ключи и начинаются обычные параметры.
Эта последовательность — двойное тире (—). Оболочка использует её для указания позиции, на которой заканчивается список ключей. После того, как скрипт обнаружит признак окончания ключей, то, что осталось, можно, не опасаясь ошибок, обрабатывать как параметры, а не как ключи. Рассмотрим пример:
Этот сценарий использует команду break для прерывания цикла while при обнаружении в строке двойного тире.
Вот что получится после его вызова.

Обработка ключей и параметров командной строки
Как видно, когда скрипт, разбирая переданные ему данные, находит двойное тире, он завершает обработку ключей и считает всё, что ещё не обработано, параметрами.
Обработка ключей со значениями
По мере усложнения ваших скриптов, вы столкнётесь с ситуациями, когда обычных ключей уже недостаточно, а значит, нужно будет использовать ключи с некими значениями. Например, вызов сценария в котором используется подобная возможность, выглядит так:
Скрипт должен уметь определять, когда вместе с ключами командной строки используются дополнительные параметры:
Вызовем этот скрипт в таком виде:
Посмотрим на результаты его работы.

Обработка параметров ключей
В данном примере в конструкции case обрабатываются три ключа. Ключ -b требует наличия дополнительного параметра. Так как обрабатываемый ключ находится в переменной $1 , соответствующий ему параметр будет находиться в $2 (тут используется команда shift , поэтому, по мере обработки, всё, что передано сценарию, сдвигается влево). Когда с этим мы разобрались, осталось лишь извлечь значение переменной $2 и у нас будет параметр нужного ключа. Конечно, тут понадобится ещё одна команда shift для того, чтобы следующий ключ попал в $1 .
Использование стандартных ключей
При написании bash-скриптов вы можете выбирать любые буквы для ключей командной строки и произвольно задавать реакцию скрипта на эти ключи. Однако, в мире Linux значения некоторых ключей стали чем-то вроде стандарта, которого полезно придерживаться. Вот список этих ключей:
Если вы работаете в Linux, вам, скорее всего, знакомы многие из этих ключей. Использовав их в общепринятом значении в своих скриптах, вы поможете пользователям взаимодействовать с ними, не беспокоясь о чтении документации.
Получение данных от пользователя
Ключи и параметры командной строки — это отличный способ получить данные от того, кто пользуется скриптом, однако в некоторых случаях нужно больше интерактивности.
Иногда сценарии нуждаются в данных, которые пользователь должен ввести во время выполнения программы. Именно для этой цели в оболочке bash имеется команда read .
Эта команда позволяет принимать введённые данные либо со стандартного ввода (с клавиатуры), либо используя другие дескрипторы файлов. После получения данных, эта команда помещает их в переменную:
Обратите внимание на то, что команда echo , которая выводит приглашение, вызывается с ключом -n . Это приводит к тому, что в конце приглашения не выводится знак перевода строки, что позволяет пользователю скрипта вводить данные там же, где расположено приглашение, а не на следующей строке.

Обработка пользовательского ввода
При вызове read можно указывать и несколько переменных:
Вот что выведет скрипт после запуска.

Несколько переменных в команде read
Если, вызвав read , не указывать переменную, данные, введённые пользователем, будут помещены в специальную переменную среды REPLY :

Использование переменной среды REPLY
Если скрипт должен продолжать выполнение независимо от того, введёт пользователь какие-то данные или нет, вызывая команду read можно воспользоваться ключом -t . А именно, параметр ключа задаёт время ожидания ввода в секундах:
Если данные не будут введены в течение 5 секунд, скрипт выполнит ветвь условного оператора else , выведя извинения.

Ограничение времени на ввод данных
Ввод паролей
Иногда то, что вводит пользователь в ответ на вопрос скрипта, лучше на экране не показывать. Например, так обычно делают, запрашивая пароли. Ключ -s команды read предотвращает отображение на экране данных, вводимых с клавиатуры. На самом деле, данные выводятся, но команда read делает цвет текста таким же, как цвет фона.
Вот как отработает этот скрипт.

Ввод конфиденциальных данных
Чтение данных из файла
Команда read может, при каждом вызове, читать одну строку текста из файла. Когда в файле больше не останется непрочитанных строк, она просто остановится. Если нужно получить в скрипте всё содержимое файла, можно, с помощью конвейера, передать результаты вызова команды cat для файла, конструкции while , которая содержит команду read (конечно, использование команды cat выглядит примитивно, но наша цель — показать всё максимально просто, ориентируясь на новичков; опытные пользователи, уверены, это поймут).
Напишем скрипт, в котором используется только что описанный подход к чтению файлов.
Посмотрим на него в деле.

Чтение данных из файла
Тут мы передали в цикл while содержимое файла и перебрали все строки этого файла, выводя номер и содержимое каждой из них.
Итоги
Сегодня мы разобрали работу с ключами и параметрами командной строки. Без этих средств диапазон использования скриптов оказывается чрезвычайно узким. Даже если скрипт написан, что называется, «для себя». Тут же мы рассмотрели подходы к получению данных от пользователя во время выполнения программы — это делает сценарии интерактивными.
В следующий раз поговорим об операциях ввода и вывода.
Уважаемые читатели! Спасибо вам за то, что делитесь опытом в комментариях к предыдущим частям этого цикла материалов. Если вам есть что сказать об обработке всего того, что можно передать в скрипт при запуске или во время его работы, уверены, многим будет интересно об этом почитать.