Урок 5. Перенаправление вывода и конвейеры
Главная сила командной строки — в соединении простых команд. Одна выбирает строки, другая сортирует, третья считает, и вместе они за секунду делают то, на что в окнах ушёл бы час. Для этого нужно понять, куда команды пишут результат и откуда читают данные.
Три потока
У каждой команды есть три стандартных потока:
| Номер | Имя | Что это |
|---|---|---|
| 0 | stdin, ввод | откуда команда читает данные; обычно — клавиатура |
| 1 | stdout, вывод | куда пишет результат; обычно — экран |
| 2 | stderr, ошибки | куда пишет сообщения об ошибках; тоже экран |
На экране вывод и ошибки выглядят одинаково, но это два разных потока, и направлять их можно по отдельности.
Вывод в файл: > и >>
ls /etc > list.txt
date >> list.txt>записывает вывод в файл. Если файла нет — он создаётся, если есть — стирается и пишется заново.>>дописывает в конец файла, ничего не стирая.
> стирает файл молча, без вопроса. sort data.txt > data.txt оставит пустой файл: оболочка очищает файл ещё до того, как sort начнёт его читать. Пишите результат в новый файл.
Защита от случайной перезаписи — команда set -o noclobber: после неё > откажется писать в существующий файл.
Ошибки отдельно: 2>
ls /etc /nonexistent > out.txt 2> errors.txt
find / -name "*.conf" 2>/dev/null
ls /etc /nonexistent > all.txt 2>&1
ls /etc /nonexistent &> all.txt2>— направить в файл поток ошибок (номер 2);2>>— дописать./dev/null— особый файл-«пустота»: всё, что туда записано, исчезает.2>/dev/nullпрячет ошибки.> all.txt 2>&1— вывод в файл, а ошибки — туда же, куда вывод.&>— короткая запись того же в bash.
Порядок важен: > file 2>&1 пишет в файл всё, а 2>&1 > file — только вывод, а ошибки остаются на экране. Оболочка читает перенаправления слева направо, и 2>&1 означает «туда, куда сейчас идёт вывод».
Ввод из файла: <
wc -l < list.txt< подаёт файл на вход команде вместо клавиатуры. Похожая конструкция — here-document: строки прямо из команды или скрипта, до строки-метки:
cat > hello.txt << 'EOF'
Первая строка
Вторая строка
EOFВсё между << 'EOF' и строкой EOF попадает на вход cat, а та пишет его в файл. Кавычки вокруг EOF запрещают подстановку переменных внутри.
Конвейер: |
Знак | (pipe, труба) передаёт вывод одной команды на вход следующей:
ls /etc | wc -l
history | grep ssh
ps aux | grep nginx
ls -l /usr/bin | lessПервая строка считает файлы в /etc, вторая ищет в истории команды с ssh, третья — процессы nginx, четвёртая позволяет листать длинный вывод. По трубе идёт только вывод; чтобы туда попали и ошибки, пишут 2>&1 |.
Считать и сортировать: wc, sort, uniq
Создайте файл со списком городов — по одному в строке:
printf '%s\n' минск гомель минск брест минск гомель > cities.txt$ wc -l cities.txt
6 cities.txt
$ sort cities.txt
брест
гомель
гомель
минск
минск
минск
$ sort -u cities.txt
брест
гомель
минск
$ sort cities.txt | uniq -c
1 брест
2 гомель
3 минск
$ sort cities.txt | uniq -c | sort -rn
3 минск
2 гомель
1 брестwcсчитает:-l— строки,-w— слова,-c— байты.sortсортирует строки:-n— как числа,-r— в обратном порядке,-u— без повторов,-h— размеры вида2Kи1G.uniqубирает соседние повторы,uniq -cещё и считает их. Поэтому передuniqпочти всегда стоитsort.
Последняя цепочка — частый приём: «что встречается чаще всего». Так, например, ищут адреса, с которых больше всего запросов к сайту:
cut -d ' ' -f 1 /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -n 10cut -d ' ' -f 1 оставляет из каждой строки только первое поле до пробела — адрес посетителя; head -n 10 — десять первых строк результата.
Вывод и на экран, и в файл: tee
ping -c 4 debian.org | tee ping.txt
echo "192.168.1.10 server" | sudo tee -a /etc/hoststee пишет полученное в файл и одновременно показывает на экране; -a — дописать, а не перезаписать.
Вторая строка решает частую загадку: sudo echo "…" >> /etc/hosts не работает, потому что >> выполняет ещё ваша оболочка без прав root, а sudo относится только к echo. sudo tee открывает файл уже с правами root.
Несколько команд в строке: ; && ||
cd ~/practice; ls
mkdir backup && cp *.txt backup/
ping -c 1 192.168.1.1 > /dev/null || echo "Роутер не отвечает";— выполнить по очереди, что бы ни случилось;&&— вторая команда выполнится, только если первая прошла успешно;||— вторая выполнится, только если первая закончилась ошибкой.
Коротко
- Три потока: ввод (0), вывод (1), ошибки (2).
>— в файл с перезаписью,>>— дописать,2>— ошибки,> файл 2>&1или&>— всё в один файл./dev/null— выбросить вывод;<— подать файл на вход.|передаёт вывод следующей команде;sort | uniq -c | sort -rn— что встречается чаще всего.tee— и на экран, и в файл;sudo tee— запись в системный файл.&&— дальше при успехе,||— при ошибке.