Bash Days | Linux | DevOps
23.3K subscribers
156 photos
24 videos
678 links
Авторский канал от действующего девопса

Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу.

Автор: Роман Шубин
Реклама: @maxgrue

MAX: https://max.ru/bashdays

Курс: @tormozilla_bot
Блог: https://bashdays.ru
Download Telegram
Вот всё трём мы с тобой за бест-практики, но практически ничего не разбираем по бэд-практикам.

Давай это исправлять в контексте Bash скриптов.

Временами будет много, временами мало и банально, но постараюсь всё разжевать и сделать интересную выжимку из наблюдений.

Естественно будет серебряная пуля — как сделать правильно.


Ну чё, готов? Тогда поехали!

Почему при копировании файлов, необходимо использовать кавычки?

Допустим, у тебя есть переменная $file, в которой как ни странно хранится имя файла. И есть $target, в ней мы указываем путь куда скопировать файл.

Если мы пишем:

cp $file $target


То возникает проблема, Если имя файла содержит пробелы, то Bash ясен хуй разобьет эту строку на пробелы:

file="You can suck my dick.avi"


Команда превращается в такое:

cp You can suck my dick.avi /tmp


И это воспримется интерпретатором как копирование нескольких файлов:

You
can
suck
my
dick.avi


Дальше. Если в имени файла ($file) будут символы *, ?, [ ], то это интерпретируется как шаблон для поиска файла.

Так называемое — Pathname Expansion.


Ага. Теперь если в имени файла содержится символ -, к примеру твой файл называется: -bashdays.txt, то команда cp расценит, что ты указал флаг и выебет тебя в глаз.

cp -bashdays.txt /tmp

cp: ну ты ебать инвалид -- 'h'
Try 'cp --help' for more information.


Как правильно?

Вот так:

cp -- "$file" "$target"


Кавычки в данном контексте предотвратят разделение на пробелы и ошибочное расширение подстановок.

Но если сделать так:

cp "-bashdays.txt" "/tmp"

cp: еще и баран -- 'h'
Try 'cp --help' for more information.


Чтобы не быть «инвалидом и бараном» нужно после cp вхерачить --.

Эти два тире напомнят cp что дальше идут только файлы, а никакие-то флаги.

Каков итог?

Думаю ты и сам выводы сделал. Всегда пиздярь кавычки вокруг переменных в Bash.

Даже если работает без кавычек это ничего не значит, не ровен час получишь по ебалу.

Например твой скрипт будет выполняться в другом окружении, где $IFS (разделитель слов) изменён или файлы содержат пробелы и спецсимволы.


В общем сразу мотай на ус эту тему, подстели соломку и пиши скрипты как профи.

tags: #bash #badpractices #bestpractices

🔔 @bashdays➡️ @gitgate
Please open Telegram to view this post
VIEW IN TELEGRAM
109
Продолжаем погружаться в Бэд-Практики!

предыдущие посты о том, что это такое ищи по тегу #badpractices


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

Как это победить мы с тобой уже знаем, завернуть в кавычки и кинуть два дефиса:

cp -- "$file" "$target"


Что означают 2 дефиса опять же смотри предыдущие посты по тэгу #badpractices


Ок. Минус этого метода — его нужно сука запомнить и не забывать использовать каждый раз при передачах файлов. Вообще не интуитивно.

Второй способ разруливания этой ситуации — указать путь к файлу.

Смотри. Если перед именем файла добавить ./ (означает текущую папку), то даже если файл называется -bashdays.txt он будет передан в команду правильно.

for i in ./*.txt; do
cp "$i" /tmp
done


В этом случае cp не затроит и выполнит задуманное.

Ну и еще вариант на закуску.

Можно просто ебануть ./ перед именем файла при передачах в команду:

for i in *.txt; do
cp "./$i" /tmp
done


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

Выводы

Лучший вариант — всегда указывать путь к файлу (относительный ./ или полный /home/user/...). Это избавит тебя от большинства проблем с файлами которые начинаются с дефиса.

tags: #bash #badpractices #bestpractices

🔔 @bashdays➡️ @gitgate
Please open Telegram to view this post
VIEW IN TELEGRAM
40
Когда в Bash ты сравниваешь две переменные, важно не проебаться с кавычками.

[ $foo = "bar" ]


В этом примере если переменная $foo будет пустой, то по итогу ты попадешь в просак:

[ = "bar" ]

bash: [: =: unary operator expected


Логично вылезет ошибка, потому что «=» ожидает два значения. Чтобы избежать этой ситуации, на помощь приходят — кавычки.

[ "$foo" = "bar" ]


Теперь всё в поряде. Ошибки никакой нет.

Но Bash не пальцем деланный, поэтом сравнить две переменные можно иначе.

[[ $foo == bar ]]


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

Есть еще легаси способ:

[ x"$foo" = x"bar" ]


В современном мире ты вряд ли с ним столкнешься, но в каких-то допотопных скриптах вполне можешь найти.

Если $foo пустая, то без x получится:

[ = bar ]


А с x будет:

[ x = xbar ]


В [[ ... ]] переменные не разделяются на слова, даже если содержат пробелы.


foo="hello bashdays"
[[ $foo = "hello bashdays" ]]


А если сделать так:

foo="hello bashdays"
[ $foo = "hello bashdays" ]


Получишь ошибку: bash: [: too many arguments

Все это справедливо для Bash. Если пишешь под sh, то твой путь это одинарные скобки [...].

А еще в двойных скобках можно использовать шаблоны:

foo="hello bashdays"
[[ $foo == h* ]]


Вернёт true, потому что foo начинается с «h».

Либо написать сложное условие:

[[ $foo = "bar" || $bar = "baz" ]]


В одинарных кавычках это выглядело бы так:

[ "$foo" = "bar" -o "$bar" = "baz" ]


Выводы:

Всё что тебе нужно знать это первые два способа:

[ "$foo" = "bar" ]
[[ $foo == bar ]]


Это трувей, бестпрактика и мастхев.

Изучай.

tags: #bash #badpractices #bestpractices

🔔 @bashdays➡️ @gitgate
Please open Telegram to view this post
VIEW IN TELEGRAM
86
Представь что у тебя есть переменная:

f="My Documents/file.txt"


И в скрипте мы делаем так:

cd $(dirname "$f")


Это ошибочный вариант, бэд мать его практика.

Команда cd $(dirname "$f") должна вернуть путь к папке, где лежит файл.

НО! Результат этой команды разбивается на части, если в нём есть пробелы.

Например:

dirname "My Documents/file.txt"


Выдаст: My Documents

А если так:

cd My Documents


Логично, получаем ошибку:

cd: No such file or directory: My


Bash думает что это два отдельных слова, а не один путь.

➡️ Бест-практика

cd -P -- "$(dirname -- "$f")"


1. Кавычки защищают результат команды от разбиения.
2. И cd получит целый путь, даже если в нём есть пробелы.

Как работают кавычки

- Когда Bash видит $(...), он воспринимает это как отдельную область, некий «уровень».

- Кавычки внутри $(...) работают только внутри.

- Кавычки снаружи не объединяются с внутренними.

Наглядно, можно представить так:

cd "$( dirname "$f" )"


Внутренние кавычки "$f" защищают переменную f

Внешние кавычки "" защищают результат dirname "$f"

Теперь даже если переменная будет содержать пробелы команда не разобьётся на части.

tags: #bash #badpractices #bestpractices

🔔 @bashdays➡️ @gitgate
Please open Telegram to view this post
VIEW IN TELEGRAM
75