Errors in linux scripting

How to redirect standard (stderr) error in bash

I am trying to redirect bash message into file named output.log. But, it is not getting redirected. How do I redirect both standard output and standard error in bash shell? In Linux, how do I redirect error messages?

Standard error (also known as stderr) is the default error output device. Use stderr to write all system error messages. The number (FD – File Descriptors) two (2) denotes the stderr. The default stderr is the screen or monitor. Standard output (also known as stdout) is used by a command to writes (display) its output. The default stdout is the screen. It is denoted by one number (1).

Tutorial details
Difficulty level Easy
Root privileges No
Requirements Linux, macOS or Unix-like OS with Bash
Est. reading time 3 minutes

2> is input redirection symbol and syntax is:

  1. To redirect stderr (standard error) to a file:
    command 2> errors.txt
  2. Let us redirect both stderr and stdout (standard output):
    command &> output.txt
  3. Finally, we can redirect stdout to a file named myoutput.txt, and then redirect stderr to stdout using 2>&1 (errors.txt):
    command > out 2>errors.txt

Make sure you use >> for appending data/log if the file already has data. For instance:

How to redirect standard error in bash

Run find command and save all error messages to find.error.txt file:
find / -name «*.conf» 2> find.error.txt
You can view find.error.txt with the cat command:
cat find.error.txt
Sample outputs:

You need to use “2>” when you want to redirect stderr to a file. You can redirect stdout to file named results.txt and stderr to file named errors.txt:
find / -name «*.conf» >results.txt 2>error.txt
Verify results with the cat command:
cat results.txt
cat error.txt
This is useful in shell scripts or any other purpose.

How to redirect standard error and standard output in bash

You can send both stdout and stderr to a file named output.txt
command &>output.xt
find / -name «*.pl» &>filelist.txt
Please note that both errors and actual output of the find command stored into a file:
cat filelist.txt
Sample outputs:

  • No ads and tracking
  • In-depth guides for developers and sysadmins at Opensourceflare✨
  • Join my Patreon to support independent content creators and start reading latest guides:
    • How to set up Redis sentinel cluster on Ubuntu or Debian Linux
    • How To Set Up SSH Keys With YubiKey as two-factor authentication (U2F/FIDO2)
    • How to set up Mariadb Galera cluster on Ubuntu or Debian Linux
    • A podman tutorial for beginners – part I (run Linux containers without Docker and in daemonless mode)
    • How to protect Linux against rogue USB devices using USBGuard

Join Patreon

Summary

Command Description/Purpose
command 2>filename Redirect stderr to filename
command >output.txt 2>error.log
cat output.txt error.txt
Redirect stderr to file named error.log and stdout to file named output.txt
command &> filename Redirect stderr and stdout to filename
command 2>&- Just suppress error messages. No file created. No error message displayed on screen
command 1>&2
Sample code:
Redirect error messages to standard output. Useful in shell script when you need to forcefully display error messages on screen

For more info see bash man page online or read it at the cli by using the man command:
man bash

🐧 Get the latest tutorials on Linux, Open Source & DevOps via

Category List of Unix and Linux commands
Documentation help • mandb • man • pinfo
Disk space analyzers df • duf • ncdu • pydf
File Management cat • cp • less • mkdir • more • tree
Firewall Alpine Awall • CentOS 8 • OpenSUSE • RHEL 8 • Ubuntu 16.04 • Ubuntu 18.04 • Ubuntu 20.04
Linux Desktop Apps Skype • Spotify • VLC 3
Modern utilities bat • exa
Network Utilities NetHogs • dig • host • ip • nmap
OpenVPN CentOS 7 • CentOS 8 • Debian 10 • Debian 8/9 • Ubuntu 18.04 • Ubuntu 20.04
Package Manager apk • apt
Processes Management bg • chroot • cron • disown • fg • glances • gtop • jobs • killall • kill • pidof • pstree • pwdx • time • vtop
Searching ag • grep • whereis • which
Shell builtins compgen • echo • printf
Text processing cut • rev
User Information groups • id • lastcomm • last • lid/libuser-lid • logname • members • users • whoami • who • w
WireGuard VPN Alpine • CentOS 8 • Debian 10 • Firewall • Ubuntu 20.04

Comments on this entry are closed.

The numbers are actually file descriptors.

  • 0 = stdin
  • 1 = stdout
  • 2 = stderr

yes they are. thanks for comment.

Hi, Vitek!
It seems there is a mistake in your article, specifically the fifth example in your conclusive summarizing table is wrong in my opinion. I had tried to post you a reply, but it turned to be too long and the site refused to accept it. So I designed it as a text file, zipped it as a tar archive and uploaded to a filehosting. Please take some time, download it and read my message. Perhaps I’m wrong, still it seems to me, I’ve found a flaw in your article.

I can’t find your zip file. However, I updated my 5th example.

I have read your article “How to Redirect Standard Error in Bash” on the link https://www.cyberciti.biz/faq/how-to-redirect-standard-error-in-bash/ dedicated to the redirection of standard input/output streams,
however I couldn’t understand the meaning of your last instruction in the article and the example below.

Redirect error messages to standard output. Useful in shell script when you need
to forcefully display error messages on screen

The 2>&1 command really redirects stderr to stdout, but it seems in most cases this construction won’t work as it was thought out. In your example you redirect the stderr of echo, but echo always sends its output to stdout, not stderr, thus this redirection will take no effect and the “File not found” message will be sent to stdout any case. On the other hand, if the standard output has been already redirected to some file, say “msg.txt”, the 2>&1 construction will redirect stderr to the same “msg.txt” file and put all your error messages together with normal output.

I think what you really meant was the construction 1>&2 which redirects stdout to stderr. Then the standard output of the script may be redirected to some file or a pipe, still the error messages will appear on the screen or a terminal. So your instruction possibly should be rewritten in some way like:

Redirect error messages from standard output to standard error stream. Useful in a shell script when you need to forcefully display error messages on the screen, no matter was the script’s output redirected to a file or a pipe or not. The construction is useful with commands like echo or printf, which always print the text to the standard output, and makes them print error messages to the standard error stream.

Per contra, the 2>&1 operator is useful when you want your script’s or program’s error messages to get to the same stream as normal output. In that case it must be preceded by the stdout redirection, otherwise it won’t work. For example,

As far as I know, it’s a common practice to use in modern shells a brief simplified notation:

instead of the old traditional

but the meaning of both notations (modern simplified and the old verbose one)
is quite the same. Please look through my post and comment it. I’m not a shell programming expert, so I may be wrong, but it seems I’ve found a small mistake in your article.

Thanks. I fixed the page. I appreciate your feedback.

Источник

Частые ошибки программирования на Bash

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

Большинство имеющихся руководств посвящено тому, как надо писать. Я же расскажу о том, как писать НЕ надо 🙂

Данный текст является вольным переводом вики-страницы «Bash pitfalls» по состоянию на 13 декабря 2008 года. В силу викиобразности исходника, этот перевод может отличаться от оригинала. Поскольку объем текста слишком велик для публикации целиком, он будет публиковаться частями.

1. for i in `ls *.mp3`

Одна из наиболее часто встречающихся ошибок в bash-скриптах — это циклы типа такого:

Это не сработает, если в названии одного из файлов присутствуют пробелы, т.к. результат подстановки команды ls *.mp3 подвергается разбиению на слова. Предположим, что у нас в текущей директории есть файл 01 — Don’t Eat the Yellow Snow.mp3 . Цикл for пройдётся по каждому слову из названия файла и $i примет значения: «01» , «-» , «Don’t» , «Eat» , «the» , «Yellow» , «Snow.mp3» .

Заключить всю команду в кавычки тоже не получится:

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

На самом деле использование ls совершенно излишне: это внешняя команда, которая просто не нужна в данном случае. Как же тогда правильно? А вот так:

Предоставьте bash’у самому подставлять имена файлов. Такая подстановка не будет приводить к разделению строки на слова. Каждое имя файла, удовлетворяющее шаблону *.mp3 , будет рассматриваться как одно слово, и цикл пройдёт по каждому имени файла по одному разу.

Дополнительные сведения можно найти в п. 20 Bash FAQ.

Внимательный читатель должен был заметить кавычки во второй строке вышеприведённого примера. Это плавно подводит нас к подвоху №2.

2. cp $file $target

Что не так в этой команде? Вроде бы ничего особенного, если вы абсолютно точно знаете, что переменные $file и $target не содержат пробелов или подстановочных символов.

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

Без двойных кавычек скрипт выполнит команду cp 01 — Don’t Eat the Yellow Snow.mp3 /mnt/usb , и вы получите массу ошибок типа cp: cannot stat `01′: No such file or directory . Если в значениях переменных $file или $target содержатся символы *, ?, [..] или (..), используемые в шаблонах подстановки имен файлов («wildmats»), то в случае существования файлов, удовлетворяющих шаблону, значения переменных будут преобразованы в имена этих файлов. Двойные кавычки решают эту проблему, если только «$file» не начинается с дефиса — , в этом случае cp думает, что вы пытаетесь указать ему еще одну опцию командной строки.

Один из способов обхода — вставить двойной дефис ( — ) между командой cp и её аргументами. Двойной дефис сообщит cp , что нужно прекратить поиск опций:

Однако вам может попасться одна из систем, в которых такой трюк не работает. Или же команда, которую вы пытаетесь выполнить, не поддерживает опцию — . В таком случае читайте дальше.

Ещё один способ — убедиться, что названия файлов всегда начинаются с имени каталога (включая ./ для текущего). Например:

Даже если у нас есть файл, название которого начинается с «-«, механизм подстановки шаблонов гарантирует, что переменная будет содержать нечто вроде ./-foo.mp3 , что абсолютно безопасно для использования вместе с cp .

3. [ $foo = «bar» ]

В этом примере кавычки расставлены неправильно: в bash нет необходимости заключать строковой литерал в кавычки; но вам обязательно следует закавычить переменную, если вы не уверены, что она не содержит пробелов или знаков подстановки (wildcards).

Этот код ошибочен по двум причинам:

1. Если переменная, используемая в условии [ , не существует или пуста, строка

будет воспринята как

что вызовет ошибку «unary operator expected». (Оператор «=» бинарный, а не унарный, поэтому команда [ будет в шоке от такого синтаксиса)
2. Если переменная содержит пробел внутри себя, она будет разбита на разные слова перед тем, как будет обработана командой [ :

Даже если лично вам кажется, что это нормально, такой синтаксис является ошибочным.

Правильно будет так:

Но этот вариант не будет работать, если $foo начинается с — .

В bash для решения этой проблемы может быть использовано ключевое слово [[ , которое включает в себя и значительно расширяет старую команду test (также известную как [ )

Внутри [[ и ]] уже не нужно брать в кавычки названия переменных, поскольку переменные больше не разбиваются на слова и даже пустые переменные обрабатываются корректно. С другой стороны, даже если лишний раз взять их в кавычки, это ничему не повредит.

Возможно, вы видели код типа такого:

Хак x»$foo» требуется в коде, который должен работать в шеллах, не поддерживающих [[ , потому что если $foo начинается с — , команда [ будет дезориентирована.

Если одна из частей выражения — константа, можно сделать так:

Команду [ не волнует, что выражение справа от знака «=» начинается с — . Она просто использует это выражение, как строку. Только левая часть требует такого пристального внимания.

4. cd `dirname «$f»`

Пока что мы в основном говорим об одном и том же. Точно так же, как и с раскрытием значений переменных, результат подстановки команды подвергается разбиению на слова и раскрытию имен файлов (pathname expansion). Поэтому мы должны заключить команду в кавычки:

Что здесь не совсем очевидно, это последовательность кавычек. Программист на C мог бы предположить, что сгруппированы первая и вторая кавычки, а также третья и четвёртая. Однако в данном случае это не так. Bash рассматривает двойные кавычки внутри команды как первую пару, и наружные кавычки — как вторую.

Другими словами, парсер рассматривает обратные кавычки ( ` ) как уровень вложенности, и кавычки внутри него отделены от внешних.

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

Кавычки внутри $() сгруппированы.

5. [ «$foo» = bar && «$bar» = foo ]

Нельзя использовать && внутри «старой» команды test или её эквивалента [ . Парсер bash’а видит && вне скобок и разбивает вашу команду на две, перед и после && . Лучше используйте один из вариантов:

Обратите внимание, что мы поменяли местами константу и переменную внутри [ — по причинам, рассмотренным в предыдущем пункте.

То же самое относится и к || . Используйте [[ , или -o , или две команды [ .

6. [[ $foo > 7 ]]

Если оператор > используется внутри [[ ]] , он рассматривается как оператор сравнения строк, а не чисел. В некоторых случаях это может сработать, а может и не сработать (и это произойдёт как раз тогда, когда вы меньше всего будете этого ожидать). Если > находится внутри [ ] , всё ещё хуже: в данном случае это перенаправление вывода из файлового дескриптора с указанным номером. В текущем каталоге появится пустой файл с названием 7 , и команда test завершится с успехом, если только переменная $foo не пуста.

Поэтому операторы > и [ .. ] или [[ .. ]] использовать нельзя.

Если вы хотите сравнить два числа, используйте (( )) :

Если вы пишете для Bourne Shell (sh), а не для bash, правильным способом является такой:

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

Двойные квадратные скобки также поддерживают такой синтаксис:

7. count=0; grep foo bar | while read line; do ((count++)); done; echo «number of lines: $count»

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

Каждая команда в конвейере выполняется в отдельной подоболочке (subshell), и изменения в переменной внутри подоболочки не влияют на значение этой переменной в родительском экземпляре оболочки (т.е. в скрипте, который вызвал этот код).

В данном случае цикл for является частью конвейера и выполняется в отдельной подоболочке со своей копией переменной $count , инизиализированной значением переменной $count из родительской оболочки: «0». Когда цикл заканчивается, использованная в цикле копия $count отбрасывается и команда echo показывает неизменённое начальное значение $count («0»).

Обойти это можно несколькими способами.

Можно выполнить цикл в своей подоболочке (слегка кривовато, но так проще и понятней и работает в sh):

Чтобы полностью избежать создания подоболочки, используйте перенаправление (в Bourne shell (sh) для перенаправления также создаётся subshell, поэтому будьте внимательны, такой трюк сработает только в bash):

Предыдущий способ работает только для файлов, но что делать, если нужно построчно обработать вывод команды? Используйте подстановку процессов:

Ещё пара интересных способов разрешения проблемы с субшеллами обсуждается в Bash FAQ #24.

8. if [grep foo myfile]

Многих смущает практика ставить квадратные скобки после if и у новичков часто создаётся ложное впечатление, что [ является частью условного синтаксиса, так же, как скобки в условных конструкциях языка C.

Однако такое мнение — ошибка! Открывающая квадратная скобка ( [ ) — это не часть синтаксиса, а команда, являющаяся эквивалентом команды test , лишь за тем исключением, что последним аргументом этой команды должна быть закрывающая скобка ] .

Как видите, в синтаксисе if нет никаких [ или [[ !

Ещё раз, [ — это команда, которая принимает аргументы и выдаёт код возврата; как и все нормальные команды, она может выводить сообщения об ошибках, но, как правило, ничего не выдаёт в STDOUT.

if выполняет первый набор команд, и в зависимости от кода возврата последней команды из этого набора определяет, будет ли выполнен блок команд из секции «then» или же выполнение скрипта продолжится дальше.

Если вам необходимо принять решение в зависимости от вывода команды grep , вам не нужно заключать её в круглые, квадратные или фигурные скобки, обратные кавычки или любой другой синтаксический элемент. Просто напишите grep как команду после if :

Обратите внимание, что мы отбрасываем стандартный вывод grep : нам не нужен результат поиска, мы просто хотим знать, присутствует ли строка в файле. Если grep находит строку, он возвращает 0, и условие выполняется; в противном случае (строка в файле отсутствует) grep возвращает значение, отличное от 0. В GNU grep перенаправление >/dev/null можно заменить опцией -q , которая говорит grep ‘у, что ничего выводить не нужно.

9. if [bar=»$foo»]

Как было объяснено в предыдущем параграфе, [ — это команда. Как и в случае любой другой команды, bash предполагает, что после команды следует пробел, затем первый аргумент, затем снова пробел, и т.д. Поэтому нельзя писать всё подряд без пробелов! Правильно вот так:

bar , = , «$foo» (после подстановки, но без разделения на слова) и ] являются аргументами команды [ , поэтому между каждой парой аргументов обязательно должен присутствовать пробел, чтобы шелл мог определить, где какой аргумент начинается и заканчивается.

10. if [ [ a = b ] && [ c = d ] ]

Снова та же ошибка. [ — команда, а не синтаксический элемент между if и условием, и тем более не средство группировки. Вы не можете взять синтаксис C и переделать его в синтаксис bash простой заменой круглых скобок на квадратные.

Если вы хотите реализовать сложное условие, вот правильный способ:

Заметьте, что здесь у нас две команды после if, объединённые оператором &&. Этот код эквивалентент такой команде:

Если первая команда test возвращает значение false (любое ненулевое число), тело условия пропускается. Если она возвращает true , выполняется второе условие; если и оно возвращает true , то выполняется тело условия.

Продолжение следует.

Первая публикация этого перевода происходила на страницах моего блога.

Источник

Читайте также:  Internet explorer для windows embedded
Оцените статью