Одинарные или двойные кавычки в терминале — и куда пропали 5 долларов

Попробуй в терминале:
echo "Скидка $5 сегодня"
Получишь Скидка сегодня. Пять долларов исчезли. Без ошибки, без предупреждения.
Теперь то же с одинарными кавычками: echo 'Скидка $5 сегодня'. Всё на месте.
В Python или JavaScript разницы между ' и " почти нет. В терминале это два разных инструмента. Перепутаешь — и команда сделает не то, причём молча.
Главное отличие в одной фразе
- Одинарные кавычки
'...'— «бери буквально». Внутри не происходит ничего:$,!,\, обратные кавычки — просто символы. - Двойные кавычки
"..."— «склей в одну строку, но подставь значения». Внутри работают$ПЕРЕМЕННАЯ,$(команда)и, в интерактивном терминале,!.
Обе защищают от разрезания по пробелам. Это общее. Разница — в том, что происходит со спецсимволами внутри.
Сравнение по пунктам
$ — подстановка переменных.
'...': остаётся символом.'$HOME'— это пять букв."...": подставляет значение."$HOME"— это/home/me.
Отсюда пропавшие доллары: $5 — это пятый аргумент скрипта. В терминале он пустой, его и подставило.
$(...) — результат команды.
'...': не выполняется."...": выполняется."Сегодня $(date +%F)"вставит дату.
! — повтор из истории.
'...': просто восклицательный знак."...": в интерактивном bash и zsh работает как команда истории.echo "Готово!!"напечатает не «Готово!!», а «Готово» плюс твою предыдущую команду. Одиночный!в конце строки обычно безопасен, а!!и!слово— нет.
\ — экранирование.
'...': обратная косая — обычный символ. Экранировать внутри одинарных кавычек нельзя вообще ничего."...": экранирует четыре символа:$,",\и обратную кавычку."цена \$5"спасёт доллары.
Пробелы.
- Обе одинаково защищают:
"my file.txt"и'my file.txt'— один аргумент, а не два. Про то, как без кавычек ломаются имена с пробелами, есть отдельный разбор — почему скрипт ломается на пробелах.
Где это стреляет в реальной работе
Коммиты. git commit -m "Починил $PATH в конфиге" — и в историю уйдёт весь твой PATH вместо слова. Сообщения с $ и ! пиши в одинарных кавычках. Это касается и агентов: если Claude Code или Codex собирает команду с текстом, именно здесь чаще всего бьётся сообщение.
JSON в curl. JSON внутри полон двойных кавычек, поэтому снаружи нужны одинарные:
curl -X POST https://api.example.com/users \
-H 'Content-Type: application/json' \
-d '{"name": "Ann", "role": "admin"}'
Но если нужно вставить переменную — внутри одинарных она не сработает. Приём: закрыть одинарные кавычки, вставить переменную в двойных, открыть снова:
-d '{"name": "'"$NAME"'"}'
Выглядит как азбука Морзе, но работает: три кусочка склеиваются в одну строку. Когда JSON больше пары полей, надёжнее собрать его через jq -n --arg name "$NAME" '{name: $name}' или heredoc.
Регулярки, awk, sed. Там много $ и \, которые должны дойти до программы нетронутыми. Почти всегда — одинарные: awk '{print $2}'. В двойных $2 превратится в пустоту ещё до awk.
Переменные в скриптах. Тут наоборот: "$FILE" и "$@" — всегда в двойных. Значение подставится, и пробелы в нём не разрежут аргумент.
Как вставить одинарную кавычку внутрь одинарных
Никак — экранирование внутри не работает. Но можно схитрить двумя путями:
echo 'it'\''s' # закрыть, экранированная ', открыть
echo $'it\'s' # особые кавычки $'...' понимают \' и \n
Второй вариант, $'...', полезно знать и для переносов: echo $'строка 1\nстрока 2'.
Как увидеть, что дойдёт до программы
Гадать не нужно — есть команда-рентген. printf печатает каждый аргумент в своих скобках:
NAME="Ann Lee"
printf '[%s]\n' $NAME # [Ann] и [Lee] — два аргумента
printf '[%s]\n' "$NAME" # [Ann Lee] — один
printf '[%s]\n' '$NAME' # [$NAME] — буквально
Поставь printf '[%s]\n' перед любым хитрым куском — и сразу видно, сколько аргументов получится и что в каждом. Это быстрее, чем запускать настоящую команду и разбираться, почему она удалила или отправила не то.
Кому что подойдёт
Без «зависит от ситуации» — вот правило, которое закрывает 95% случаев:
- Текст, который должен дойти буквально — сообщения коммитов, JSON, регулярки, awk/sed, пароли со спецсимволами — одинарные.
- Всё, где есть твоя переменная или команда — двойные, и переменную оборачивай в них всегда, даже если «там точно без пробелов».
- Сомневаешься — начни с одинарных. Худшее, что случится: переменная не подставится, и ты сразу это увидишь. С двойными ошибка бывает тихой: пропал кусок текста, а команда «успешно» отработала.
В zsh на Mac всё так же?
Да, правила те же: одинарные — буквально, двойные — с подстановкой, !! в двойных тоже раскрывается. В PowerShell на Windows логика похожая, но экранирование другое — там это обратная кавычка.
А в Python и JavaScript есть такая разница?
В Python нет: 'a' и "a" одинаковы. В JavaScript подстановку делают обратные кавычки: `Привет, ${name}` — по смыслу это ближе к двойным кавычкам терминала.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.





