Новички в программировании на Bash рано или поздно столкнутся с /dev/null и другим непонятным жаргоном: > /dev/null 2>&1. Это может показаться запутанным, но это довольно просто для понимания и является фундаментальной частью программирования оболочки. Итак, давайте разберемся с пошаговыми примерами.

Начнем с того, что /dev/null - это специальный файл, который в системах Unix называется нулевым устройством. В просторечии его также называют битовым ведром или черной дырой, потому что он немедленно отбрасывает все, что в него записано, и возвращает только конец файла EOF при чтении.

Давайте посмотрим, что произойдет, когда мы попытаемся написать в него с помощью оператора перенаправления файлов (>).

# First let's try writing to this file.
$ echo 'text' > /dev/null
# Upon inspection, we see that the write was successfully. 
$ echo $?
0

Символ $? - это специальная переменная, которая всегда содержит статус выхода предыдущей команды; он будет перезаписываться каждый раз, когда вы запускаете новую команду. По соглашению, код выхода 0 указывает, что предыдущая команда была успешной, в то время как большее значение указывает код ошибки для этой конкретной программы.

Например, если мы найдем ls на страницах руководства, мы увидим, что код выхода 1 соответствует незначительной проблеме.

Давайте посмотрим на другой пример. Для следующих двух команд: первая (ls) - допустимая команда, а вторая (ls -0) - недопустимая команда, потому что она содержит недопустимый параметр -0.

Это допустимая команда:

$ ls
Applications   Documents      Library        Music          Public
$ echo $?
0

Теперь посмотрим на недопустимую команду:

$ ls -0
ls: illegal option -- 0
usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]
$ echo $?
1

Проблема со вторым сценарием заключается в том, что он отображает все сообщения об ошибках в STDERR. Однако для наших скриптов мы хотим подавить сообщения об ошибках. К счастью, есть способ делать именно то, что мы хотим.

Попробуем еще раз с > /dev/null 2>&1:

$ ls -0 > /dev/null 2>&1
$ echo $?
1

Обратите внимание, что на этот раз мы не увидели сообщений об ошибках. Чтобы сломать это, мы подавляем вывод ошибки (stderr) команды ls -0, перенаправляем его на стандартный вывод (stdout), записывая его в /dev/null, тем самым немедленно отбрасывая его. Символ >& - это оператор, который копирует вывод первого файлового дескриптора (2) и перенаправляет на вывод второго файлового дескриптора (1).

Теперь давайте посмотрим, что представляют собой числа в 2>&1, посмотрев на эту диаграмму файловых дескрипторов.

Мы можем проверить это, выполнив вывод в обычный файл вместо /dev/null.

$ ls -0 > /tmp/devnull 2>&1
$ echo $?
1
$ cat /tmp/devnull
ls: illegal option -- 0
usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]

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

function cmd_exists() {
  command -v $1 > /dev/null 2>&1
}
# cmd_exists ls; echo $?
# cmd_exists sl; echo $?

Надеюсь, /dev/null вместе с перенаправлением вывода, статусами выхода и файловыми дескрипторами должны иметь смысл, поскольку они являются фундаментальными для программирования на Bash. Есть много других операторов ввода-вывода, каждый из которых имеет свои конкретные цели, которые вы можете просмотреть здесь: