Разобрать путь без basename и dirname
path="/var/log/nginx/access.log.tar.gz"
name="${path##*/}" # access.log.tar.gz
dir="${path%/*}" # /var/log/nginx
Замерил тысячу итераций в цикле:
basename — 1107 мс, подстановка — 5 мс. Разница в двести раз, и это не про скорость самой утилиты, а про форк процесса на каждый вызов.Собрать файлы в массив вместо ls
shopt -s nullglob
files=(/var/log/nginx/*.log)
cp -- "${files[@]}" /backup/logs/
Нюанс: без
nullglob массив по несуществующей маске не пустой. Проверил — в нём оказался один элемент, сама строка /var/log/nginx/*.nosuch, и cp уедет с несуществующим файлом. shopt -s nullglob заставляет пустой glob разворачиваться в ноль элементов.Сравнить вывод двух команд без временных файлов
diff <(ls -1 dir1) <(ls -1 dir2)
<(...) подставляет путь вида /dev/fd/63, за которым стоит обычный pipe — проверил через ls -l. Нюанс: код возврата команды внутри скобок теряется, diff его не увидит. И это только bash: в dash тот же синтаксис даёт Syntax error, так что для #!/bin/sh не годится.Задать дефолт и проверить обязательные переменные
: "${TIMEOUT:=30}"
: "${DB_USER:?не задана}"
Нюанс: двоеточие в
:? обязательно. Вариант ${DB_USER?...} из подборок срабатывает только когда переменная не объявлена вовсе — пустую строку он пропускает, и скрипт идёт дальше с пустым логином. С :? тот же случай падает с кодом 127. То же и с :-: он подставляет дефолт, но не присваивает, переменная остаётся пустой.Собрать тайминги шагов скрипта
PS4='+ ${EPOCHREALTIME} '
set -x
Нюанс: в подборках сюда пишут
PS4='+ $(date "+%s.%N") => ' — и это форк date на каждую строку трассировки, в посте про избавление от форков. Встроенная EPOCHREALTIME даёт то же время с микросекундами и без единого процесса.А что вы чаще выносите из скриптов — cut и awk или всё-таки оставляете, потому что читается понятнее?
#Linux #Bash #Shell #Scripting #DevOps