Шелл скрипты vs python/Perl
Кто вообще пишет шелл скрипты в 2019’ом? Хороший вопрос. Что же, я пишу. ¯_(ツ)_/
На это есть веские причины, они описаны здесь и здесь, но всё вращается вокруг двух вещей:
- Командная строка представлена во всех Unix системах и использует встроенные фичи операционной системы.
- Командная строка — это «интерактивная командная функция», позволяющая принимать команды пользователя в процессе выполнения этих команд.
Аргументы
Когда вам необходимо передать аргумент (или ожидать его) в скрипт (так же, как передаётся параметр в функцию), вы будете использовать что-то вроде $1 в качестве первого параметра, $2 в качестве второго. Вот пример того, как это выглядит:
Скрипт run_this.sh:
echo "The input message was $1."
Выполнение:
./run_this.sh userInput
The input message was userInput.
Обратите внимание, что параметры отделены пробелом, поэтому если вы хотите ввести строку как параметр, содержащий пробел, это будет выглядеть примерно так: ./run_this.sh «user input» . «user input» будет считаться как $1 целиком.
Если вы не уверены, как долго будет продолжаться ввод пользователем, и вы хотите захватить всё что он введёт, используйте [email protected]. В следующем примере я взял всю строку и вывел её слово за словом. Я разбил слова в соответствии с пробелами и поместил их в массив.
Скрипт run_this.sh:
userInputs=([email protected]) for i in "${userInputs[@]}";; do echo "$i" done
Выполнение:
./run_this.sh who knows how long this can go who knows how long this can go
Функции
Если вы занимаетесь программированием, вы должны быть знакомы с понятием функций. По сути, это набор команд/операций, которые вы можете выполнять снова и снова. Вместо того, чтобы писать эти команды по несколько раз в коде, вы просто помещаете их в функцию. Затем просто вызываете эту функцию, тем самым эффективно уменьшая объём кода.
Примечание: если вы не знали, LOC (lines of code) плохая метрика для определения чего-либо в программировании. Это сказал не я, Билл Гейтс:
Так выглядит обычная функция:
# Declaring the function doSomething() { } # Calling the function doSomething
Выглядит довольно просто. Далее поговорим о нескольких различиях между функциями в шелл скриптах и обычном языке программирования.
Параметры
Если вы передаёте параметр в функцию в Java, то нужно объявить его при объявлении функции. Это выглядит так:
public static void main(String[] args) { doSomething("random String"); } private static void doSomething (String words) { System.out.println(words); }
В шелл параметры вообще не требуют объявления типов или имён. Каждый из них подобен отдельному сценарию, который живёт в самом сценарии. Если вы хотите использовать параметр, просто передайте его и вызывайте так, как будто вы принимаете вход для этого скрипта на верхнем уровне. Что-то вроде этого:
doSomething() { echo $1 } doSomething "random String"
- Похожим образом, если вы хотите принять всё, используйте [email protected] вместо $1. Потому что $1 берёт только первый ввод (а $2 — второй ввод и т.д.).
- Функции должны объявляться раньше, чем они вызываются (обычно в начале файла, перед любыми основными операциями).
Возврат
Давайте создадим скрипт с именем run_this.sh:
doSomething() { echo "magic" return 0 } output=`doSomething` echo $output
Теперь запустим его и посмотрим, что присвивается переменной output.
$ ./run_this.sh
magic
Обратите внимание, что вместо 0 на выходе мы видим magic, потому что, когда вы выполняете output=`doSomething`, назначается сообщение output вместо возвращаемого значения. Так происходит, поскольку выходные сообщения — это способ коммуникации в шелл сценариях почти во всех случаях.
В каких случаях имеет смысл использовать вызов return? Когда вы используете его как часть выражения if. Например так:
Скрипт run_this.sh:
doSomething() { echo "magic" return 0 } if doSomething; then echo "Its true!" fi
Выполнение:
./run_this.sh
Its true!
В этом случае return 0 означает true, когда return 1 в традиционном булевом смысле означает false.
Multi-line echo
Есть несколько способов вывести сообщение, состоящее из нескольких строк. Самый простой способ — использовать echo несколько раз:
echo "line1" echo "line2" echo "line3"
Это не самый элегантный способ, хотя и рабочий. Вместо этого можно использовать cat << EOF. Вот так:
cat << EOF line1 line2 line3 EOF
Обратите внимание, что перед EOF не должно быть ничего, включая пробелы и табуляцию. В if выражении можно записать это так:
if [ "a" == "a" ]; then cat << EOF line1 line2 line3 EOF fi
Имейте в виду, что даже сами сообщения выравниваются влево. Это связано с тем, что, если вы сделаете табуляцию, выходное сообщение, выводимое в командной строке, тоже будет с табуляцией. Кроме того, если в EOF есть табуляция, шелл обычно выдаёт ошибку и завершает сценарий.
Флаги/Параметры
Вы, вероятно, встречали скрипты или команды, в которые можно добавлять флаги (а иногда и аргументы для некоторых флагов). Что-то вроде: git commit -a -m «Some commit message».
Вот небольшой пример того, как это выглядит:
Скрипт run_this.sh:
while getopts ac: opt; do case $opt in a) echo ""a" was executed." ;; c) echo ""c" was executed with parameter "$OPTARG"." ;; ?) echo "Invalid option: -$opt" exit 1 ;; :) echo "option -$opt requires an argument." exit 1 ;; esac done
Выполнение:
./run_this.sh ./run_this.sh -a "a" was executed. ./run_this.sh -c option -c requires an argument. ./run_this.sh -c abcd "c" was executed with parameter "abcd". ./run_this.sh -a -c abc "a" was executed. "c" was executed with parameter "abc". ./run_this.sh -x Invalid option: -x
В этом примере различия между параметрами -a и -c заключаются в том, что в строке getopts после c стоит двоеточие (:). Это сообщает программе ожидать параметр. Ещё следует иметь в виду, что параметры должны быть объявлены в алфавитном порядке. Если вы объявите что-то вроде acb, то b будет проигнорировано. В таком случае использование флага -b приведёт к ошибке.
Читайте также
Специально для сайта ITWORLD.UZ. Новость взята с сайта NOP::Nuances of programming