Обработка сценария Bash с CRLF (возврат каретки )в Linux, как в MSYS2?

У меня пока недостаточно баллов, чтобы прокомментировать другой ответ, но, основываясь на вашей ветке комментариев, вам нужно удалить или исправить сломанные пакеты (простой способ — просто удалить, поэтому запуститеsudo apt-get remove 389-ds-console)

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

2
03.04.2020, 12:22
4 ответа

Насколько мне известно, нет способа заставить Bash принимать окончание строк в стиле Windows -.

В ситуациях, связанных с Windows, обычной практикой является полагаться на способность Git автоматически преобразовывать окончания строк -при фиксации, используя флаг конфигурации autocrlf. См., например, документацию GitHub по окончаниям строк , которая не относится к GitHub. Таким образом, файлы фиксируются в репозитории с окончанием строки в стиле Unix -и преобразуются соответствующим образом для каждой клиентской платформы.

(Противоположная проблема не является проблемой. :MSYS2 отлично работает с окончаниями строк в стиле Unix -в Windows.)

2
28.04.2021, 23:19

Для этого следует использовать binfmt _misc [1].

Сначала определите магию, которая обрабатывает файлы, начинающиеся с #! /bin/bash<CR><LF>, затем создайте для нее исполняемый интерпретатор. Интерпретатором может быть другой скрипт:

INTERP=/path/to/bash-crlf

echo ",bash-crlf,M,,#! /bin/bash\x0d\x0a,,$INTERP," > /proc/sys/fs/binfmt_misc/register
cat > "$INTERP" <<'EOT'; chmod 755 "$INTERP"
#! /bin/bash
script=$1; shift; exec bash <(sed 's/\r$//' "$script") "$@"
EOT

Проверь:

$ printf '%s\r\n' '#! /bin/bash' pwd >/tmp/foo; chmod 755 /tmp/foo
$ cat -v /tmp/foo
#! /bin/bash^M
pwd^M
$ /tmp/foo
/tmp

У примера интерпретатора есть две проблемы:1. поскольку он передает скрипт через -недоступный для поиска файл (канал ), bash будет читать его побайтно, очень неэффективно, и 2. любые сообщения об ошибках будут ссылаться на /dev/fd/63или подобное вместо имени исходного скрипта.

[1] Конечно, вместо использования binfmt _misc вы можете просто создать /bin/bash^Mсимволическую ссылку на интерпретатор, которая также будет работать в других системах, таких как OpenBSD:

ln -s /path/to/bash-crlf $'/bin/bash\r'

Но в Linux исполняемые файлы shebanged не имеют преимуществ перед binfmt _misc, и размещение мусора внутри системных каталогов — неправильная стратегия, и любой системный администратор заставит качать головой ;-)

2
28.04.2021, 23:19

Хорошо, я нашел обходной путь через:

"Соединенные" символические ссылки

Modern unix systems have a way to make arbitrary data appear as a file, independently of how it's stored: FUSE. With FUSE, every operation on a file (create, open, read, write, list directory, etc.) invokes some code in a program, and that code can do whatever you want. See Create a virtual file that is actually a command. You could try out scriptfs or fuseflt, or if you're feeling ambitious, roll your own.

... и Создать виртуальный файл, который на самом деле является командой

You may be looking for a named pipe.

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

Здесь у меня есть оригинал tmp.shс окончаниями строки CRLF в /tmp; кулак, давайте создадим именованный канал:

tmp$ mkfifo ftmp.sh

Теперь, если вы запустите эту команду:

tmp$ dos2unix <tmp.sh >ftmp.sh

... вы заметите, что он блокируется; тогда, если вы это сделаете, скажите:

~$ cat /tmp/ftmp.sh | hexdump -C
00000000  65 63 68 6f 20 22 74 65  73 74 69 6e 67 22 0a 73  |echo "testing".s|
00000010  74 61 74 20 2e 0a 65 63  68 6f 20 22 74 65 73 74  |tat..echo "test|
00000020  69 6e 67 20 61 67 61 69  6e 22 0a                 |ing again".|
0000002b

... вы заметите, что преобразование было выполнено -и после того, как команда catвыполнила свою работу, команда dos2unix <tmp.sh >ftmp.sh, которая ранее была заблокирована, завершилась.

Итак, мы можем настроить dos2unixзапись в именованный канал в «бесконечном» цикле while:

tmp$ while [ 1 ] ; do dos2unix <tmp.sh >ftmp.sh ; done

... и даже если это «жесткий» цикл, это не должно быть проблемой, так как большую часть времени команда внутри цикла while блокируется.

Тогда я смогу:

~$ bash /tmp/ftmp.sh
testing
  File:.
  Size: 4096        Blocks: 8          IO Block: 4096   directory
Device: 801h/2049d  Inode: 5276132     Links: 7
...
testing again
$

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

Что хорошо в этом подходе, так это то, что я могу открыть оригинал tmp.shв текстовом редакторе; и напишите новый код -с окончаниями CRLF -, затем сохраните tmp.sh; и запуск bash /tmp/ftmp.shпод Linux запустит последнюю сохраненную версию.

Проблема в том, что такие команды, как read -p "Enter user: " user, которые полагаются на стандартный ввод терминала, не будут выполняться; вернее, не провалится, а если попробуешь, скажи так/tmp/tmp.sh

echo "testing"
stat.
echo "testing again"
read -p "Enter user: " user
echo "user is: $user"

... то это будет вывод:

$ bash /tmp/ftmp.sh
testing
  File:.
  Size: 4096        Blocks: 8          IO Block: 4096   directory
...
 Birth: -
testing again
Enter user: tyutyu
user is: tyutyu
testing
  File:.
  Size: 4096        Blocks: 8          IO Block: 4096   directory
...
 Birth: -
testing again
Enter user: asd
user is: asd
testing
...

... и так далее -то есть stdin с клавиатуры в терминале интерпретируется правильно, но по какой-то причине скрипт начинает зацикливаться, и выполняется с самого начала снова и снова (чего не происходит, если у нас нет команды read -p...в оригинале tmp.sh). Может быть, есть какие-то вещи для перенаправления (, например. добавление некоторого 0>1&или чего-то еще к whileкоманде цикла ;на самом деле, у меня был скрипт .shс wget, который также начинал зацикливаться, и простое добавление явного exitв конец скрипта .sh, похоже, работало, чтобы остановить цикл скрипта ), который мог обрабатывать это тоже, -, но пока скрипт, который мне нужно использовать, не имеет read -pподобных команд, поэтому этот подход может сработать для меня.

0
28.04.2021, 23:19

Вы можете вставить решетку (#)в конце каждой строки в ваших bash-скриптах. Таким образом, оболочки в Unix будут рассматривать CR просто как комментарий и не будут обращать на него внимания.

"Hex-говорение", любая строка должна заканчиваться

0x23 0x0D 0x0A

Пример:

echo "testing" #
stat. #
echo "testing again" #
-1
18.06.2021, 08:00

Теги

Похожие вопросы