Перейти к главному содержимому

Функции в bash

Задать функцию

Функции в bash можно задавать двумя способами:

# Способ 1
function_name () {
  commands
}

# Способ 2
function function_name {
  commands
}

Простые функции можно объявлять в одну строку. При этом пробелы между фигурными скобками и телом функции важны!. И последним в теле должен быть ; (точка с запятой).

Объявление функций в одну строку:

# Способ 1
function_name () { commands; }

# Способ 2
function function_name { commands; }

Итого по объявлению функций:

  • Тело функций (всё что между фигурными скобками) должно отделяться от самих фигурных скобок переносом строки или пробелами;
  • Определение функции не вызывает её (как и в нормальных языках);
  • Определение функции должно быть выше чем её вызовы;
  • Тело однострочных функций должно заканчиваться ; (точкой с запятой).

Переменные

Глобальные переменные видны в функциях и могут быть модифицированы в функциях. Локальные переменные (область видимости внутри функции) должны объявляться с ключевым словом local.

Локальные переменные имеют приоритет над глобальными если используется одно и то же имя.

#!/bin/bash

var1='A'
var2='B'

my_function () {
  local var1='C'
  var2='D'
  echo "Inside function: var1: $var1, var2: $var2"
}

echo "Before executing function: var1: $var1, var2: $var2"

my_function

echo "After executing function: var1: $var1, var2: $var2"

Вывод этого скрипта:

Before executing function: var1: A, var2: B
Inside function: var1: C, var2: D
After executing function: var1: A, var2: D

Параметры

Чтобы передать параметры в функцию надо просто написать их после вызова, разделяя пробелами. Имеет смысл заключать их в кавычки, тогда можно передавать параметры с пробелами.

  • Внутри функции доступ к параметрам осуществляется через переменные $1, $2, $3 и т.д.
  • Переменная $0 содержит имя самой функции.
  • Переменная $# содержит количество переданных параметров.
  • Переменные $* и $@ содержать все парамеры, переданные функцию.

Отличия переменных $* и $@

  • Если эти переменные НЕ заключать в кавычки, то они эквивалентны;
  • В кавычках "$*" раскрывается в одну строку "$1 $2 ... $n";
  • В кавычках "$@" раскрывается в разные строки "$1" "$2" ... "$n".

Пример:

#!/bin/bash

greeting () {
  echo "Hello $1"
}

greeting "World"

Возвращаемые значения

В отличие от функций в "настоящих" языках программирования, функции в Bash не позволяют возвращать значения как это принято. Когда функция bash заканчивает выполнение, ее возвращаемое значение это статус последней выполненной команды в теле функции, обычно 0 при успешном завершении, число 1-255 код ошибки.

Это число можно указать явно при использовании команды return, после чего оно будет сохранено в специальной переменной $?. Команда return прерывает выполнение функции (как и в обычных языках), а код ошибки можно рассматривать как статус выполнения.

Пример:

#!/bin/bash

my_function () {
  echo "some result"
  return 55
}

my_function
echo $?

Вывод этого скрипта:

some result
55

Чтобы по-настоящему что-то вернуть из функции надо использовать что-то другое. Самый простой вариант - присвоить что-то глобальной переменной:

#!/bin/bash

my_function () {
  func_result="some result"
}

my_function
echo $func_result

Вывод этого скрипта:

some result

Есть способ получше. Отправить требуемое возвращаемое значение на вывод (при помощи echo или printf, например):

#!/bin/bash

my_function () {
  local func_result="some result"
  echo "$func_result"
}

func_result="$(my_function)"
echo $func_result

Вывод этого скрипта:

some result

Тут вместо простого вызова (который просто напечатает строку) вызов функции "оборачивается" в оператор $(...), после чего переменная будет содержать то, что функция "хотела" напечатать.

Переопределение команд

Можно сделать функцию с именем, таким же как существующая команда. В этом случае, вместо команды будет вызываться функция. так можно добавлять, например, дополнительные опции во все вызовы команд сразу, или ещё как-то шаманить, чтоб не править много мест в скрипте сразу.

Пример:

#!/bin/bash

#overriding command
echo(){
    builtin echo "The name is : $1"
}

echo "Edward III"

Вывод этого скрипта:

The name is : Edward III

SSH через прокси

Для работы ssh через прокси используется может использоваться ряд программ:

Для того, чтобы подключаться через прокси ко всем или выборочным серверам надо прописать в файле config (~/.ssh/config) соответствующие настройки. Там можно настроить и другие параметры: имя пользователя, порт и т. п.

Работает и под Windows тоже (proxytunnel уж точно):

Пример:

# для примера: ip-адрес прокси 1.1.1.1 порт 8080

Host имя_хоста1
  ProxyCommand connect -H 1.1.1.1:8080 %h %p

Host имя_хоста2
  ProxyCommand corkscrew 1.1.1.1 8080 %h %p

Host имя_хоста3
  ProxyCommand proxytunnel -q -p 1.1.1.1:8080 -d %h:%p -H "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Win32)"

PuTTY

PuTTY умеет работать через прокси. Для этого в настройках подключения есть отдельная вкладка Proxy. Если нужно для проксирования вызвать внешнюю команду (например, тот же proxytunnel), то это можно сделать, указав в Proxy type не традиционные SOCKS или HTTP, а local (run subprogram to connect).

А в поле Command... вписать строку, аналогичную настройкам ssh:

proxytunnel -p 1.1.1.1:8080 -d %host:%port -H "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Win32)"

PuTTY via local proxy

Копирование метаданных с одного mp3 в другой (ffmpeg)

Файл mp3copy_id.bat следующего содержания:

@echo off

:: имя второго файла без пути и расширения
set F=%~n2
:: расширение второго файла
set E=%~x2

ffmpeg -i "%1" -y -f ffmetadata _metadata.txt

ffmpeg -i "%2" -f ffmetadata -i _metadata.txt -c copy -map_metadata 1 "%F%.1%E%"

del _metadata.txt

Запускать так:

mp3copy_id <src_mp3_file> <dest_mp3_file>

Скрипт создаст третий файл (медиа скопировано со второго, метаданные с первого). Имя файла будет такое же как у второго, но с добавленной .1 в имя файла.

QEMU run

Скрипт для запуска qemu с типовыми ключами (и образом CD в качестве опционального параметра).

#!/bin/bash

# Имя файла образа жесткого диска
IMG=./img/main_disk.img

if [[ "$OSTYPE" == "linux-gnu" ]]; then
  mkdir -p tmp
  CMDLINE=qemu-system-x86_64
  OPTS="-cpu qemu64 -enable-kvm -cpu host -hdb fat:rw:./tmp"
else
  CMDLINE=qemu-system-x86_64
  OPTS="-cpu qemu64"
fi

if [ $# -gt 0 ]; then
echo "external iso as cdrom $1"
CDROM=-cdrom $1 -boot d
else
CDROM=
fi

$CMDLINE \
    -hda $IMG \
    $CDROM $OPTS \
    -m 8192 \
    -vga cirrus \
    -net nic,model=rtl8139 \
    -net user \
    -usbdevice tablet \
    -vga virtio

Для начального создания образа диска можно использовать:

qemu-img create -f qcow2 main_disk.img 20G

Если надо упаковать каталог tmp в iso-образ, например, чтобы подсунуть в качестве cdrom при запуске qemu, то сделать можно так:

mkisofs -R -J -o dat.iso tmp/*

Boosty video download

Открыть страницу с видео, видеоплеер должен быть виден на странице.

В консоли средств разработчика (F12) выполнить:

document.querySelector('vk-video-player').store.actions.internal.downloadVideo()