Ошибка bash: ./myscript.sh: /bin/bash^M: bad interpreter выглядит так, будто в Linux внезапно пропал /bin/bash. На самом деле Bash почти наверняка находится на месте. Проблема обычно возникает из-за невидимого символа ^M, который попал в первую строку скрипта вместе с Windows-окончанием строки.

Чаще всего такая ситуация появляется после переноса shell-скрипта с Windows на Linux. Windows и Unix-подобные системы используют разные последовательности символов для обозначения конца строки. Windows традиционно использует CRLF, то есть два символа CR и LF, а Linux ожидает LF. Если файл сохранить в Windows-формате и затем попытаться запустить его непосредственно в Linux, символ возврата каретки CR может стать частью имени интерпретатора в строке shebang. В результате система пытается найти не /bin/bash, а фактически путь /bin/bash с дополнительным невидимым символом.

Именно поэтому в сообщении появляется загадочное:

id="3r8m1v"
^M

Исправить такую проблему обычно можно буквально одной командой. Для этого подходят dos2unix или sed 's/\r$//'.

Откуда в /bin/bash^M взялся лишний символ

Чтобы понять причину ошибки, сначала нужно разобраться с тем, как текстовый файл хранит конец строки.

В Unix-подобных системах конец строки обычно обозначается символом LF, который записывается как \n. В Windows исторически используется комбинация CRLF, то есть \r\n. CR означает carriage return, а LF означает line feed.

Для обычного текста разница часто незаметна. Текстовый редактор показывает одинаковые строки независимо от того, каким способом они завершены.

Но shell относится к содержимому файла гораздо строже.

Допустим, первая строка скрипта выглядит так:

#!/bin/bash

В Unix-варианте после bash находится LF:

#!/bin/bash\n

В Windows-варианте после bash находятся два символа:

#!/bin/bash\r\n

Сам по себе \r невидим при обычном просмотре файла. Однако при непосредственном запуске скрипта система читает строку #! как указание на интерпретатор. Если туда попадает CR, путь фактически превращается в:

/bin/bash\r

Такого файла не существует.

Поэтому сообщение может выглядеть следующим образом:

bash: ./myscript.sh: /bin/bash^M: bad interpreter: No such file or directory

Здесь ^M является отображением символа CR. Это не часть настоящего имени Bash и не означает, что нужно искать файл с названием /bin/bash^M.

Что такое CRLF и LF простыми словами

Представить разницу можно на обычном текстовом файле.

Unix записывает:

первая строка\n
вторая строка\n

Windows записывает:

первая строка\r\n
вторая строка\r\n

Внешне оба файла выглядят одинаково:

первая строка
вторая строка

Различие находится внутри файла.

LF состоит из одного управляющего символа. CRLF состоит из двух. Для многих современных редакторов эта разница не имеет значения, поэтому пользователь может даже не знать, в каком формате сохранён файл.

Для shell-скрипта это уже существенно.

Особенно чувствительна первая строка:

#!/bin/bash

Она называется shebang и сообщает системе, какой интерпретатор использовать для запуска файла. При запуске:

./myscript.sh

система обращается именно к этой строке.

Если там фактически записано:

#!/bin/bash\r

интерпретатор определяется неправильно. Поэтому скрипт не запускается ещё до выполнения его основной части.

Почему ошибка появляется после переноса скрипта из Windows

Самый типичный сценарий выглядит просто.

Скрипт создаётся или редактируется на Windows:

#!/bin/bash
echo "Hello"

Редактор сохраняет его с окончаниями строк CRLF.

Затем файл копируется на Linux-сервер:

Windows
   |
   | myscript.sh
   v
Linux

На Linux файл по-прежнему содержит CRLF. При этом обычный просмотр через редактор может ничего подозрительного не показать.

После команды:

./myscript.sh

появляется:

/bin/bash^M: bad interpreter

Причина не в содержимом команды echo, не в синтаксисе Bash и не в правах на сам /bin/bash. Проблема появилась раньше, на уровне окончания первой строки файла.

Такая ошибка особенно часто возникает при переносе shell-скриптов между Windows и Linux, при работе с файлами через общие каталоги, при использовании некоторых редакторов и при обмене исходниками между системами с разными настройками окончания строк.

Почему ^M появляется именно в сообщении об ошибке

Символ возврата каретки CR является управляющим символом. В обычном выводе терминала он может быть невидимым или вести себя неожиданно.

Для наглядности Unix-инструменты и сообщения оболочки используют обозначение ^M.

Поэтому:

/bin/bash^M

означает примерно:

/bin/bash + символ CR

Это очень полезная подсказка. Если после имени интерпретатора появляется именно ^M, первым делом стоит проверить окончания строк.

Похожая ситуация возникает и с другими интерпретаторами. Например:

/usr/bin/python3^M

или:

/bin/sh^M

Причина та же: после пути к интерпретатору остался символ CR.

Проблема не ограничивается Bash. Любой скрипт с shebang может столкнуться с таким поведением, если его первая строка сохранена с неподходящим окончанием.

Как проверить, действительно ли файл содержит CRLF

Перед исправлением можно проверить формат файла.

Самый простой вариант:

file myscript.sh

Если файл содержит Windows-окончания, file может сообщить:

myscript.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

Это практически прямое подтверждение причины.

Другой удобный способ посмотреть невидимые символы:

cat -A myscript.sh | head

В проблемном файле первая строка может отображаться примерно так:

#!/bin/bash^M$

Здесь:

^M

показывает CR, а:

$

показывает конец строки.

Можно проверить только первую строку:

head -n 1 myscript.sh | cat -A

Если вывод заканчивается на:

^M$

то файл имеет Windows-окончание первой строки.

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

Самый простой способ исправить файл через dos2unix

Для подобных задач существует специальная утилита dos2unix.

Если она установлена, достаточно выполнить:

dos2unix myscript.sh

Утилита преобразует окончания строк из DOS/Windows-формата CRLF в Unix-формат LF. Это как раз то преобразование, которое требуется для обычного shell-скрипта в Linux.

После этого можно снова запустить:

./myscript.sh

Если единственной причиной ошибки были CRLF, сообщение:

/bin/bash^M: bad interpreter

исчезнет.

Проверить результат можно:

file myscript.sh

и:

head -n 1 myscript.sh | cat -A

Вместо:

#!/bin/bash^M$

должно остаться обычное:

#!/bin/bash$

Что делать, если dos2unix не установлен

Устанавливать отдельную утилиту для одной операции необязательно. Ту же задачу можно выполнить стандартной командой sed.

Используется:

sed -i 's/\r$//' myscript.sh

Здесь выражение:

s/\r$//

означает удаление символа CR, если он находится в конце строки.

После обработки файл будет содержать обычные Unix-окончания строк.

Затем:

./myscript.sh

Команда sed является удобным вариантом для минимальной Linux-системы, где dos2unix не установлен. Такой способ удаления CR из строк также используется как стандартное решение проблемы с Windows-окончаниями в shell-файлах.

Чем отличаются dos2unix и sed

Для этой задачи обе команды решают одну проблему, но подход у них немного отличается.

dos2unix специально предназначен для преобразования текстовых файлов между форматами окончаний строк. Поэтому команда:

dos2unix myscript.sh

максимально наглядно показывает намерение: преобразовать файл из DOS/Windows-формата в Unix-формат.

sed выполняет более конкретную операцию:

sed -i 's/\r$//' myscript.sh

Она удаляет CR в конце каждой строки.

Для обычного shell-скрипта оба варианта подходят.

Если dos2unix уже установлен, это самый простой вариант. Если его нет, sed позволяет исправить файл без установки дополнительного инструмента.

Почему bash myscript.sh иногда работает, а ./myscript.sh не работает

Это важный момент, который часто сбивает с толку.

Предположим, есть проблемный файл:

#!/bin/bash
echo "Hello"

но он сохранён с CRLF.

Команда:

./myscript.sh

может завершиться ошибкой:

/bin/bash^M: bad interpreter

А команда:

bash myscript.sh

в некоторых случаях проходит дальше.

Причина в том, что во втором случае пользователь сам указывает интерпретатор:

bash myscript.sh

Bash открывает файл как входной сценарий, поэтому shebang первой строки не используется для выбора интерпретатора. Проблема с CR при этом всё равно остаётся внутри самого файла. Другие строки могут содержать невидимые \r, из-за которых позже появляются сообщения вроде:

$'\r': command not found

или другие странные ошибки.

Поэтому запуск через:

bash myscript.sh

не является полноценным исправлением.

Он лишь позволяет обойти проблему с shebang при конкретном запуске.

Сам файл всё равно остаётся в неправильном формате.

Почему не стоит просто запускать скрипт через bash

Если:

./myscript.sh

не работает, а:

bash myscript.sh

работает, может показаться, что проблема решена.

Но это временный обход.

У скрипта может быть правильный shebang:

#!/bin/bash

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

./myscript.sh

Кроме того, скрипт может запускаться из другого инструмента, который использует shebang автоматически. Это могут быть задания автоматизации, системные процессы или другие программы.

Если оставить CRLF, проблема может вернуться в другом месте.

Поэтому лучше исправить окончания строк самого файла:

dos2unix myscript.sh

или:

sed -i 's/\r$//' myscript.sh

После этого скрипт будет нормально запускаться непосредственно как исполняемый файл.

Нужно ли после исправления снова делать chmod +x

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

Можно проверить:

ls -l myscript.sh

Например:

-rwxr-xr-x 1 user user 842 Sep 15 10:20 myscript.sh

Буква x показывает наличие права на выполнение.

Если права отсутствуют:

-rw-r--r--

то после исправления CRLF дополнительно потребуется:

chmod +x myscript.sh

После этого:

./myscript.sh

Важно не смешивать две разные проблемы.

Ошибка:

/bin/bash^M: bad interpreter

говорит о проблеме с интерпретатором и обычно в данном случае указывает на CRLF.

Ошибка:

Permission denied

при запуске ./myscript.sh может быть связана с отсутствием права выполнения. Это уже другая причина.

Как исправить файл прямо в редакторе

Исправить окончания строк можно не только из терминала.

Многие современные редакторы показывают текущий формат окончания строк как:

CRLF

или:

LF

Если shell-скрипт предназначен для Linux, его нужно сохранить с окончаниями LF.

После смены формата файл необходимо сохранить.

Это особенно удобно, если скрипт постоянно редактируется на Windows, но выполняется в Linux. В таком случае недостаточно исправить один уже повреждённый файл. Нужно ещё настроить редактор так, чтобы новые версии скриптов сохранялись с LF.

В противном случае после следующего сохранения проблема может появиться снова.

Как CRLF может повредить не только первую строку

Первая строка является наиболее заметным местом, потому что ошибка сразу показывает:

/bin/bash^M

Но символ CR может присутствовать в конце каждой строки.

Например:

#!/bin/bash^M
echo "Hello"^M
name="Linux"^M
echo "$name"^M

После shebang Bash может начать интерпретировать \r как часть команд или аргументов.

В результате появляются сообщения вроде:

$'\r': command not found

или команды получают неожиданные аргументы.

Поэтому исправлять только первую строку вручную недостаточно. Нужно преобразовать окончания строк всего файла.

Именно поэтому команды:

dos2unix myscript.sh

и:

sed -i 's/\r$//' myscript.sh

лучше ручного удаления ^M из первой строки. Они обрабатывают весь файл.

Как проверить файл после исправления

После преобразования можно выполнить несколько простых проверок.

Сначала:

file myscript.sh

Затем:

head -n 1 myscript.sh | cat -A

Если скрипт исполняемый:

ls -l myscript.sh

И наконец:

./myscript.sh

Если скрипт содержит:

#!/bin/bash

и Unix-окончания строк, а права на выполнение установлены, запуск должен перейти к выполнению самого Bash-кода.

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

Что делать, если ^M появляется снова

Если файл регулярно переносится между Windows и Linux, одноразового исправления может быть недостаточно.

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

Windows
   |
   v
редактирование script.sh
   |
   v
CRLF
   |
   v
Linux
   |
   v
dos2unix
   |
   v
LF

После следующего редактирования на Windows файл снова сохраняется как CRLF.

Чтобы этого не происходило, нужно настроить редактор на использование LF для shell-скриптов.

Если проект хранится в Git, дополнительно можно задать правила окончания строк через .gitattributes. Например:

*.sh text eol=lf

Такой подход помогает закрепить требуемый формат для shell-скриптов и уменьшить вероятность того, что файл снова окажется с Windows-окончаниями.

Для проекта, в котором одновременно работают Windows и Linux, это особенно полезно. Иначе один участник может сохранить файл с CRLF, а другой столкнётся с ^M уже на Linux-сервере.

Почему ^M не является частью Bash

Важно не пытаться искать специальную конструкцию Bash под названием ^M.

Это не команда и не оператор.

^M является способом отображения управляющего символа CR, который оказался в файле. Сам символ связан с возвратом каретки и исторически используется как часть Windows-последовательности CRLF.

Поэтому:

/bin/bash^M

нужно читать как:

/bin/bash + лишний CR

После преобразования:

CRLF

в:

LF

лишний символ исчезает.

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

Можно ли удалить ^M с помощью tr

Да, технически это тоже возможно. Например:

tr -d '\r' < myscript.sh > myscript-fixed.sh

В результате создаётся новый файл без символов CR.

Однако для обычного shell-скрипта проще использовать:

dos2unix myscript.sh

или:

sed -i 's/\r$//' myscript.sh

sed удаляет именно CR, расположенный в конце строки, а dos2unix предназначен непосредственно для преобразования Windows-окончаний в Unix-формат.

При использовании перенаправления с tr нужно помнить о создании нового файла и отдельно учитывать его права доступа. Поэтому для повседневного исправления скриптов dos2unix или sed обычно удобнее.

Что делать, если после исправления ошибка осталась

Если после:

dos2unix myscript.sh

или:

sed -i 's/\r$//' myscript.sh

сообщение всё ещё содержит bad interpreter, не стоит автоматически считать, что Linux игнорирует исправление.

У bad interpreter есть и другие причины.

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

#!/usr/local/bin/bash

если Bash находится в другом месте.

Проверить расположение Bash можно:

command -v bash

На многих системах результатом будет:

/usr/bin/bash

или:

/bin/bash

Также можно посмотреть первую строку:

head -n 1 myscript.sh

и проверить тип файла:

file myscript.sh

Если ^M исчез, но путь к интерпретатору неправильный, это уже не проблема CRLF.

Современные версии Bash могут показывать ошибку иначе, без явного ^M, поэтому при диагностике важно смотреть не только на текст сообщения, но и на сам файл.

Почему ошибка выглядит как проблема с Bash

Название ошибки вводит в заблуждение:

bad interpreter

Пользователь видит /bin/bash и может решить, что Bash повреждён или отсутствует.

Но в классическом случае с ^M Bash находится на месте.

Проблема заключается в том, что система получила другое имя:

/bin/bash\r

Для операционной системы это не тот же самый путь, что:

/bin/bash

Даже один невидимый символ делает путь другим.

Поэтому проверка:

ls -l /bin/bash

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

Это одна из причин, почему сообщение кажется нелогичным до тех пор, пока не становится понятна разница между LF и CRLF.

Самое быстрое решение проблемы

Если вы точно видите:

bash: ./myscript.sh: /bin/bash^M: bad interpreter

то последовательность действий может быть очень короткой:

file myscript.sh
dos2unix myscript.sh
./myscript.sh

Если dos2unix не установлен:

sed -i 's/\r$//' myscript.sh
./myscript.sh

Если после этого появляется Permission denied:

chmod +x myscript.sh
./myscript.sh

Если появляется уже ошибка внутри самого скрипта, значит проблема с окончаниями строк устранена и нужно искать причину в коде.

Главное не путать эти этапы. CRLF, права на выполнение и ошибки Bash-кода являются разными проблемами.

Главное о /bin/bash^M bad interpreter

Ошибка:

bash: ./myscript.sh: /bin/bash^M: bad interpreter

в классическом случае означает, что shell-скрипт сохранён с Windows-окончаниями строк CRLF.

Linux ожидает окончание строки LF, а символ CR из пары CRLF остаётся в первой строке. В результате путь:

/bin/bash

для системы фактически превращается в:

/bin/bash\r

и такой интерпретатор не находится. Обозначение ^M в сообщении как раз указывает на этот скрытый символ.

Самый простой способ исправить файл:

dos2unix myscript.sh

Если утилиты нет:

sed -i 's/\r$//' myscript.sh

После этого скрипт можно снова запустить:

./myscript.sh

Если ошибка возникла после переноса файла из Windows, это первое, что стоит проверить. Не нужно переустанавливать Bash, менять путь к интерпретатору или переписывать скрипт только из-за появления ^M.

Важнее исправить сам формат файла. После преобразования CRLF в LF невидимый CR исчезает не только из shebang, но и из остальных строк, поэтому устраняется сразу целый класс связанных ошибок.

Чтобы проблема не возвращалась, shell-скрипты, предназначенные для Linux, лучше сохранять с окончаниями LF, а в общих проектах закреплять это правило средствами редактора или .gitattributes. Тогда перенос файла между Windows и Linux не будет каждый раз превращаться в поиск загадочного ^M.