Насколько хорошо ты знаешь bash?

Пользуешься командным интерпретатором каждый день? Готов решить несколько логических задачек и узнать что-то новое? Добро пожаловать под кат.
Часть представленных здесь задач не принесёт реальной пользы, так как затрагивает какие-то сложные граничные случаи. Другая же часть будет полезна тем, кто постоянно использует шелл и читает чужие скрипты.
Примечание: на момент написания статьи автор использовал bash 4.4.12(1)-release в подсистеме Linux на Windows 10. Сложность задач различная.
Задача 1
$ cat 1
The cake is a lie!
$ cat 1 | head | tail | sed -e 's/alive/dead/g' | tee | wc -l > 1
Что будет выведено на экран?
Ничего.
После интерпретации команды, но до запуска всех программ bash работает с указанными потоками ввода-вывода. Таким образом файл 1 очищается перед запуском первой программы и cat открывает уже очищенный файл.
Задача 2
$ cat file1
I love UNIX!
$ cat file2
I don't like UNIX
$ cat file1
Что будет выведено на экран?
I love UNIX!
Некоторые программы забивают на stdin, когда указаны файлы.
Задача 3
$ cat file
Just for fun
$ cat file 1>&2 2>/dev/null
Что будет выведено на экран?
Just for fun
1>&2 перенаправляет первый поток во второй, однако, это не так. Рассмотрим команду из задания. В начале интерпретации введённой команды таблица потоков выглядит так: | 0 | 1 | 2 |
| stdin | stdout | stderr |
bash обнаруживает последовательность
1>&2 и копирует содержимое ячейки 2 в ячейку 1: | 0 | 1 | 2 |
| stdin | stderr | stderr |
После обнаружения последовательности
2>/dev/null интерпретатор записывает значение в ячейку 2, оставляя другие ячейки нетронутыми: | 0 | 1 | 2 |
| stdin | stderr | /dev/null |
bash выводит так же и поток ошибок, так что на мы обнаруживаем на экране текст файла.
Задача 4
Как вывод stdout отправить на stderr, а вывод stderr, наоборот, на stdout?
4>&1 1>&2 2>&4
Принцип ровно как и в предыдущей задаче. Именно поэтому нам требуется дополнительный поток для временного хранения.
Задача 5
Дан файл test.sh
#!/bin/bash
ls $*
ls $@
ls "$*"
ls "$@"
Выполняются команды:
$ ls
1 2 3 test.sh
$ ./test.sh 1 2 3
Что выведет скрипт?
1 2 3
1 2 3
ls: cannot access '1 2 3': No such file or directory
1 2 3
Без кавычек переменные $* и $@ ничем не отличаются и раскрываются во все заданные позиционные аргументы скрипта, разделённые пробелом. В кавычках способ раскрытия меняется: $* превращается в »$1 $2 $3», а $@ в свою очередь в »$1» »$2» »$3». Так как файла »1 2 3» в каталоге нет, ls выводит ошибку
Задача 6
Создадим в текущей директории файл -c c правами 755 и таким содержимым:
#!/bin/bash
echo $1
Обнулим переменную $PATH и попытаемся выполнить:
$ PATH=
$ -c "echo SURPRISE"
Что будет выведено на экран? Что произойдет, если повторить ввод последней команды?
Первый раз будет выведено SURPRISE, второй раз echo SURPRISE
Таким образом, перед выполнением наша команда выглядит так:
/bin/bash -c "echo SURPRISE"
И, как следствие, выполняется совершенно не то, что мы хотели.
Если выполнить второй раз, то шелл подберёт информацию о -c из кэша и выполнит его уже верно. Единственный способ защититься от столь неожиданного эффекта — добавить два минуса в шебанг.
Задача 7
$ ls
file
$ cat <$(ls)
$ cat <(ls)
Что будет выведено на экран в первом и во втором случае?
В первом будет выведено содержимое файла file, во втором — имя файла.
cat
Во втором случае
<(ls) будет заменён на именованный пайп, соединённый входом с stdout ls, и выходом с stdin cat.После подстановки команда приобретёт вид:
cat /dev/fd/xx
Задача 8
$ TEST=123456
$ echo ${TEST%56}
Что будет выведено на экран?
1234
$ TEST=file.ext
$ echo ${TEST%.ext}
file
Задача 9
$ echo ${friendship:-magic}
Что будет выведено на экран?
Если переменная friendship определена, то содержимое переменной. Иначе — magic.
В документации эта магия называется «unset or null» и позволяет использовать заданное дефолтное значение переменной в одну строчку.
Задача 10
while true; false; do
echo Success
done
Что будет выведено на экран?
Ничего
Операторы while и if позволяют в условие запихать целую последовательность действий, однако результат (код возврата) будет учитываться только у последней команды. Так как там стоит false, цикл даже не начнётся.
Задача 11
$ false && true || true && false && echo 1 || echo 2
Что будет выведено на экран?
2
((((false && true) || true) && false) && echo 1) || echo 2
(((false || true) && false) && echo 1) || echo 2
((true && false) && echo 1) || echo 2
(false && echo 1) || echo 2
false || echo 2
echo 2
Замечания, пожелания и дополнительные задачи приветствуются в комментарии или ЛС.
