Любопытный случай с командами оболочки, или как «этот баг требуется POSIX» (2021)=news.ycombinator.com=

Любопытный случай с командами оболочки, или как «этот баг требуется POSIX» (2021) ( volution.ro )

panzi 23 часа назад | [–]
Да, system() определенно следует сделать устаревшим, и вы никогда не должны использовать его, если пишете новую программу. По крайней мере, в POSIX есть exec*() и posix_spawn(). В Windows такого нет, и каждая программа может анализировать строку командной строки по-разному. Вы не можете наивно написать универсальный интерфейс типа posix_spawn() для Windows, см. эту связанную CVE Rust: https://blog.rust-lang.org/2024/04/09/cve-2024-24576/ Почему это CVE в Rust, но не в каком-либо другом языке программирования? Справился ли с этим другой язык лучше? Не знаю, я просто знаю, что в документации Rust есть большое предупреждение по этому поводу ( https://doc.rust-lang.org/std/process/struct.Command.html#me… ), а вот в Java, например, его нет ( https://docs.oracle.com/javase/8/docs/api/java/lang/ProcessB… ).
прокатился 21 час назад | | [–]
Основная причина существования system() заключается в том, что люди хотят выполнять команды оболочки; некоторые сбитые с толку начинающие разработчики могут путать ее с execl(), но это не основной источник уязвимостей. Основной источник уязвимостей — «о, да, я на самом деле хотел выполнить shell».

Так что если вы просто уберете libcall, люди создадут свою собственную версию, просто выполнив execl() для /bin/sh. Если вы хотите, чтобы это изменилось, я думаю, вам нужно спросить, почему люди вообще хотят это сделать.

И ответ здесь в основном в том, что из-за философии дизайна unix оболочка чрезвычайно полезна. Есть все эти классные, маленькие утилиты и трюки, которые вы можете использовать вместо написания большого количества дополнительного кода. В Windows соглашения командной строки, особенности файловой системы и обходные пути на самом деле более многочисленны. Просто там почти нечего вызывать, поэтому вы получаете меньше ошибок.

Самый практичный способ устранить этот класс ошибок — сделать оболочку Unix менее полезной.

Галанве 22 часа назад | | | [–]
Я не понимаю, на что вы жалуетесь. Я также не понимаю, на что жалуется статья.

exec* не являются «лучшей заменой» оболочки, они просто используются для разных вариантов использования.

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

1) Обеззараживайте свои входные данные

2) Если вы хотите выполнить определенную программу, выполните ее после 1), оболочка не нужна

3) Разрешить оболочку, если нет риска инъекции

jcranmer 22 часа назад | | | [–]
В статье много внимания уделяется рассуждениям вокруг центральных моментов, вместо того чтобы рассматривать их напрямую, но основные проблемы с оболочкой сводятся к следующему:

Есть два способа представить «выполнение команды»:

1. Список строк, содержащих имя исполняемого файла (которое может быть или не быть полным путем) и его аргументы (например, const char **argv в языке C).

2. Одна строка, представляющая собой список аргументов, разделенных пробелами, со специальными символами в аргументах (включая пробелы), требующими заключения в кавычки для правильного представления.

Преобразование между этими двумя формами нетривиально. И основная проблема в том, что есть много инструментов, которые неправильно преобразуют первое во второе, просто объединяя все аргументы в одну строку и вставляя пробелы. Часть проблемы в том, что сам скрипт оболочки затрудняет преобразование, но конечный эффект заключается в том, что если вам приходится работать с командами с вводом, содержащими специальные символы (включая, но не ограничиваясь, пробелами), вы в конечном итоге просто медленно сходите с ума, пытаясь понять, как правильно заключить кавычки в кавычки, чтобы обойти сломанные инструменты.

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

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

theamk 21 час назад | | | [–]
Я думаю, что «нетривиальные» и «медленно сходящие с ума» детали случаются только если у вас нет нужных инструментов или вы не используете POSIX-совместимую систему.

В python есть “shlex.quote” и “shlex.join”. В bash есть “${env@Q}”. Я обнаружил, что они работают для меня замечательно – и я делал безумные вещи, такие как цитирование аргументов, встраивание в скрипт оболочки, цитирование скрипта снова для ssh и цитирование в третий раз для создания исполняемого файла .sh.

На других языках… да, у вас будут плохие времена. Особенно на Windows, где я бы просто сдался и перешел на WSL.

jcranmer 20 часов назад | | | [–]
Честно говоря, до сегодняшнего дня я никогда не слышал о решении @Q в Bash — я не могу найти его в https://tldp.org/LDP/abs/html/ , который является моим обычным руководством по поиску информации «как реализовать $ADVANCED_FEATURE в bash?».
o11c 19 часов назад | | | [–]
Честно говоря, многого не хватает. Я не уверен, что просто показывает его возраст, а что никогда не было. Настоящее руководство по bash весьма информативно.

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

panzi 22 часа назад | | | | [–]
Я бы сказал: не используйте оболочку, если вы хотите запустить другую программу.

Вам не нужно обрабатывать кавычки с exec*(). Вам все равно нужно обрабатывать опции, да. Но в Windows вам всегда придется обрабатывать кавычки самостоятельно, и это сложнее, чем для оболочки POSIX, и это зависит от программы. Не зная, какая программа выполняется, вы не можете знать, какой синтаксис кавычек вам нужно использовать, и, как таковая, стандартная библиотека не может написать универсальный интерфейс для передачи аргументов другому процессу безопасным способом в Windows.

Мне просто показалось, что POSIX в этом контексте особенно плох, хотя на самом деле он здесь лучше, чем Windows. Тем не менее, функция system() — это ошибка. Используйте posix_spawn(). (Примечание: не используйте _spawn*() в Windows. Это просто объединяет аргументы с пробелом между ними и без каких-либо кавычек.)

oguz-ismail 22 часа назад | | | [–]
>И все же функция system() — ошибка. Используйте posix_spawn().

Хотя это совершенно разные интерфейсы. Если бы вы реализовали system() с помощью posix_spawn(), это было бы так же плохо, как и system()

panzi 22 часа назад | | | [–]
Зачем вообще реализовывать system()?
theamk 21 час назад | | | [–]
анализировать команды из файла конфигурации? аргументы командной строки для хуков?

https://news.ycombinator.com/item?id=44239036

panzi 19 часов назад | | | [–]
Я понимаю, что это удобно для запуска таких небольших фрагментов, но я не думаю, что это стоит риска. И помещать это в файл конфигурации — это другое, ИМХО. У вас не возникнет соблазна сделать там какую-то плохую интерполяцию строк, потому что вы не можете этого сделать, если только формат файла конфигурации не поддерживает это, но тогда я критикую это. Если вам нужно передать что-то в такой фрагмент, делайте это через переменные окружения или стандартный ввод-вывод, а не через интерполяцию строк.

Если вы говорите, что не делаете таких ошибок: Да, но люди делают. Люди, которые пишут код, работающий в вашей системе.

theamk 5 часов назад | | | [–]
Но если вам нужна опция командной строки для hook, какие есть альтернативы?

Заставлять пользователя всегда создавать скрипт-оболочку? Это просто лишнее раздражение, и если пользователь плохо цитирует, у него будут те же проблемы со скриптом.

Отключить хуки вообще? Это плохая функциональность, регресс

Запрашивать несколько аргументов? Это значительно усложняет синтаксический анализ командной строки. Я не видел хороших решений для этой проблемы.

(Единственным исключением является написание оболочки команды, которая принимает ровно одну пользовательскую команду, например «timeout» или «xargs».. но они уже используют вектор аргументов вместо синтаксического анализа)

frumplestlatz 4 часа назад | | | [–]
Вы определяете формат файла конфигурации, который поддерживает только минимальный синтаксис, необходимый для указания команды с несколькими аргументами (например, аргументы разделяются пробелами, аргументы с пробелами могут быть заключены в кавычки или для их экранирования можно использовать обратные косые черты).

Затем вы преобразуете его в правильный массив аргументов и передаете его в exec*/posix_spawn.

oguz-ismail 21 час назад | | | | [–]
Потому что я не хочу реализовывать оболочку???
panzi 21 час назад | | | [–]
Если вы хотите запустить скрипт оболочки, запустите скрипт оболочки. То есть текстовый файл с установленным исполняемым битом и shebang. Если вы хотите сгенерировать скрипт оболочки на лету, чтобы затем запустить его, сделайте шаг назад и подумайте о том, что вы делаете.
oguz-ismail 4 часа назад | | | [–]
Или я могу просто использовать system(), потому что он там есть и никуда не денется.
tedunangst 21 час назад | | | [–]
https://flatt.tech/research/posts/batbadbut-you-cant-securel…
panzi 14 часов назад | | | [–]
Да, особенно эта штука с заменой переменных — просто безумие. Как можно так основательно все испортить!? Приложение B — хороший обзор. Я поражен, что Java даже не упоминает об этом в своей документации!
o11c 23 часа назад | | [–]
Это ужасно ошибочно. В половине случаев передача его в оболочку явно является функцией, например `popen(“gzip > foo.gz”)`. Если у вас есть пользовательский ввод, вы всегда должны его очищать независимо от API.

Но `ssh` заслуживает всего позора. Жаль, что в статье, полной ерунды, трудно найти настоящие проблемы.

Обратите внимание, что если вы используете несовершенную оболочку, которая не поддерживает ни `printf %q`, ни `${var@Q}`, все равно легко использовать кавычки в `sed`. Скрипты GNU `./configure` делают это внутренне, включая специальный регистр, чтобы кавычки заключали только правую часть `–arg=value`.

akdev1l 22 часа назад | | [–]
> Обратите внимание, что если вы используете несовершенную оболочку, которая не поддерживает ни `printf %q`, ни `${var@Q}`, то все равно легко использовать кавычки в `sed`. Скрипты GNU `./configure` делают это внутренне, включая специальный регистр, чтобы кавычки заключались только в правую часть `–arg=value`.

При условии, что:

1. Человек знает, что нужно делать эту странную вещь. 2. Он делает это постоянно, каждый раз. 3. Он никогда не забывает.

Также не уверен, как использовать эти решения для приведенного вами примера popen().

Правильный способ:

subprocess.run([ “gzip”, “-c”, “—-to-stdout”, user_input ], stdout=open(“foo.gz”)) И теперь мне не нужно беспокоиться ни об одной из этих странных вещей

panzi 22 часа назад | | | [–]
Вам нужно убедиться, что user_input не начинается с `-`. Это можно сделать, принудительно указав абсолютный путь. Некоторые программы принимают `–` как маркер того, что любые аргументы после него не являются опциями.
theamk 21 час назад | | | | [–]
Идея в том, что у вас есть стороннее приложение, которое может принимать параметр и передавать его popen как есть, что-то вроде “–data-handler=command”

В этом случае текущая семантика “popen” – одна команда оболочки – работает довольно хорошо. Вы можете передать ей пользовательский процесс:

–data-handler=”scripts/handle_data.py” или фрагмент оболочки:

–data-handler=”gzip -c > last_data.gz” или даже мини-скрипт оболочки:

–data-handler “jq .contents | mail -s 'Новые входящие данные' data-notify” Вот где аргументы “shell command” действительно проявляют себя – и обратите внимание, что вы не можете имитировать всю эту функциональность с помощью command vector.

akdev1l 17 часов назад | | | [–]
Да, в этом конкретном случае вам понадобится оболочка.

Но это то же самое, что сказать, что вам технически нужна SQL-инъекция, чтобы `psql -c 'command'` могла работать.

> Вы не можете смоделировать все это с помощью командного вектора

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

subprocess.run([“bash”, “-c”, data_handler]) В качестве бонуса таким образом мы получаем контроль над тем, какая оболочка используется, и я нахожу это более явным, поэтому предпочитаю именно его.

oguz-ismail 2 часа назад | | | [–]
> подпроцесс.выполнить([“bash”,

Не то же самое, это уязвимо для перехвата $PATH. Вы можете жестко закодировать путь в bash, чтобы избежать этого, но нет гарантии, что он всегда будет там. system() с другой стороны гарантированно запустит интерпретатор команд операционной системы.

hello_computer 23 часа назад | | | [–]
> статья полная чушь

Пожалуйста, расскажите подробнее. Мне кажется, это приличный список подводных камней оболочки.

bee_rider 23 часа назад | | | [–]
Это своего рода путешествие в раздражающем смысле. Например, нам действительно нужно знать все эти вещи о: эта страница руководства говорит о необходимости очистки ввода, эта — нет, бла-бла-бла.

Или давайте просто посмотрим на отрывок, вот раздел «правильное решение»:

Я подчеркнул действенные советы.

> Правильным решением было бы немедленно выбросить сломанный инструмент, надежно стереть его с жесткого диска, а затем бежать и громко кричать название этого инструмента от стыда… (Что-то вроде пути искупления из Игры престолов…)

Шутить

> Я не шучу… Подобные неисправные инструменты являются причиной множества глупых ошибок, начиная от забавных ups-rm-with-spaces (например, rm -Rf / какая-то папка с пробелами / какой-то-файл) и заканчивая серьезными проблемами безопасности, такими как ранее упомянутый shellshock…

Шуточное/бессодержательное повышение ставок.

> Итак, вы говорите, что кто-то держит вас под дулом пистолета, поэтому вы должны использовать этот инструмент? Проверьте, нет ли у сломанного инструмента флага, который отключает вызов sh -c, и вместо этого он правильно выполняет заданную команду и аргументы напрямую через execve(2). (Например, у watch есть флаг -x, как упоминалось.)

Вот он, абзац, в котором что-то есть!

> В качестве альтернативы, учитывая, что, скорее всего, рассматриваемый инструмент является проектом с открытым исходным кодом, написанным кем-то в свободное время, возможно, стоит открыть запрос на функцию, описывающую проблему, и, если возможно, внести свой вклад с помощью патча, который ее решает.

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

> Все еще безуспешно? Приготовьте попкорн и приготовьтесь к последнему блокбастеру «замысловатые решения простых проблем в городе UNIX»…

Драматическое нагнетание/шутка.

прокатился 21 час назад | | | [–]
В оригинальном посте утверждалось, что статья — чушь; вы пытаетесь оправдать это, говоря, что вам не нравится стиль письма автора. Две разные вещи…

Статья в основном верна, хотя в ней есть некоторые странные утверждения (например, ошибка Shellshock не имела ничего общего с классом ошибок, на которые жалуется статья, — это была уязвимость в самой оболочке). В ней определенно есть атмосфера «новичок ненавидит вещи, не понимая, почему они такие, какие они есть», но вам это действительно нужно время от времени. Старожилы, как правило, говорят «это было сделано так изначально по какой-то причине, и если у вас достаточно опыта, вы знаете, как с этим бороться», но то, что имело смысл 30-40 лет назад, может не иметь особого смысла сегодня.

theamk 21 час назад | | | [–]
Не знаю, «в основном» обычно означает некую большую долю, может быть, 50% или 90% в зависимости от человека. Учитывая, что выполнение команд само по себе не является ни ошибкой, ни уязвимостью безопасности (они возникают только из-за плохого или отсутствующего кавычек), большая часть статьи неверна.
pabs3 5 часов назад | | [–]
Связанные проблемы: параметры командной строки, которые разрешают выполнение кода[1], и команды, которые выполняют произвольный код из текущего каталога.

1. https://web.archive.org/web/20201111203646if_/https://www.de…

chubot 22 часа назад | | [–]
В статье упоминается printf '%q ', но его немного трудно найти. Вот удобный способ запомнить его.

Сначала определим эту функцию:

quote-argv() { printf '%q ' “$@”; } # (использует тонкую векторизацию printf по аргументам) Теперь это работает правильно:

ssh example.com “$(quote-argv ls 'файл с пробелами')” ls: невозможно получить доступ к 'файлу с пробелами': Такого файла или каталога нет В отличие от:

$ ssh example.com ls 'файл с пробелами' ls: невозможно получить доступ к 'файлу': Такого файла или каталога нет ls: невозможно получить доступ к 'с': Такого файла или каталога нет ls: невозможно получить доступ к 'пробелам': Такого файла или каталога нет И да, “скрытое argv join” в ssh ОЧЕНЬ плохо, и это повторяется во встроенной функции eval оболочки.

Они оба должны принимать только ОДИН аргумент.

По сути, это self-own, потому что пробелы — это ОПЕРАТОР в shell! (оператор, разделяющий слова)

При объединении операторов и переменных вы смешиваете код и данные, что является проблемой безопасности.

Что касается обходного пути exec, я думаю, что это также недостаток оболочки. Oils, вероятно, вырастет встроенный 'invoke', который обобщает 'command' и 'builtin', которые не являются ортогональными.

«command true» означает «внешний или встроенный» (отключение поиска функций оболочки), но должно быть что-то, что означает «только внешний».

blueflow 18 часов назад | | [–]
> скрытый argv join

Это не скрыто. Это написано на виду:

Полная командная строка может быть указана как команда, или она может иметь дополнительные аргументы. Если они указаны, аргументы будут добавлены к команде, разделенные пробелами, перед тем, как она будет отправлена на сервер для выполнения. – третья строка в `man 1 ssh`

чубот 17 часов назад | | | [–]
Он скрыт в том смысле, что создает неоднозначность на месте использования. Сравните с sudo:

$ sudo ls 'файл с пробелами' ls: невозможно получить доступ к 'файлу с пробелами': Такого файла или каталога нет Если бы ssh (и sh eval) не принимали несколько аргументов, то это даже не дошло бы до ls:

$ ssh example.com ls 'файл с пробелами' ls: невозможно получить доступ к 'файлу': Нет такого файла или каталога ls: невозможно получить доступ к 'с': Нет такого файла или каталога ls: невозможно получить доступ к 'пробелам': Нет такого файла или каталога Лучше принять argv. Или принудительно это сделать:

$ ssh example.com “ls 'file with spaces'” Итак, ясно, что это одна строка оболочки.

Принятие строки оболочки иногда допустимо, но молчаливое объединение нескольких аргументов бесполезно и небезопасно.

«RTFM» — не лучший ответ, когда речь идет о безопасности.

blueflow 17 часов назад | | | [–]
Это упрямое отношение, при котором вы вообще отказываетесь читать документацию, а затем ожидаете, что инструмент будет работать в соответствии с вашими предубеждениями.

У инструментов есть острые углы, и если вы не хотите их изучать, вас могут укусить.

immibis 0 минут назад | | | [–]
Это очень упрямое стремление защищать плохой дизайн, потому что он задокументирован.

Ошибки можно исправить.

nothrabannosir 15 часов назад | | | | [–]
Это утверждение может быть верным, не противореча ничему, что было сказано выше. В противном случае его можно использовать для оправдания любого плохого решения по проектированию.

Да, это есть в документации. Да, люди, которые внимательно читают документацию, не будут укушены. Также, да, дизайн можно улучшить, чтобы люди не совершали эту ошибку, даже не читая документацию.

Оба варианта могут быть правдой. Но сейчас мы говорим только о последнем.

blueflow 6 часов назад | | | [–]
> Однако сейчас мы говорим только о последнем.

Я удивлен, поскольку я начал эту подтему явно для того, чтобы оспорить, что соединение argv «скрыто».

чубот 15 часов назад | | | | [–]
Это ошибка проектирования, поскольку она не добавляет абсолютно никакой функциональности.

Единственное, что это добавляет, — это неуверенность.

Если бы этой функции не существовало, ее не нужно было бы документировать, и мир стал бы лучше.

blueflow 5 часов назад | | | [–]
s/лучше/соответствует моим предубеждениям/ – именно из такого отношения родилась нефтяная оболочка, верно?
chubot 5 часов назад | | | [–]
Я думаю, вы упустили изначальную мысль, которая заключается в том, что присоединение argv эквивалентно

sh -c “$1 $2 $3 $4 …” Это форма внедрения оболочки, как и

sh -c “ls $dir”, потому что там интерполяция БЕЗ экранирования.

Это должно быть:

dir=$(escape “$dir”) sh -c “ls $dir” Или просто

ls “$dir” Это не мое предубеждение — это проблема безопасности.

Это похоже на ShellShock — можно утверждать, что это было задокументированное поведение, но это все равно проблема безопасности.

blueflow 5 часов назад | | | [–]
Проблема безопасности не в интерполяции, а в том, что пользователь не цитирует свои данные.

Это похоже на curl CWE-93[1], где это было задокументировано и использовалось, и впоследствии было отклонено как проблема безопасности.

Пример для ssh:

ssh хост ls “$(quote “$dir”)” [1] https://hackerone.com/reports/3133379

Филигрань 4 часа назад | | | [–]
И все же это продолжается. Инженерная область развивается, когда люди перестают искать виноватых и начинают искать решения.
o11c 22 часа назад | | | [–]
Используйте «%q», и вы также решите проблему с именами программ, начинающимися с дефиса.
chubot 20 часов назад | | | [–]
Ах да, это умно:

$ sh -c “$(quote-argv -echo 'файл с пробелами')” sh: 0: Недопустимая опция -h $ sh -c “$(quote-argv-left -echo 'файл с пробелами')” sh: 1: -echo: не найдено По ssh:

$ ssh example.com “$(quote-argv-left -dashtest 'файл с пробелами')” -dashtest файл с пробелами

Wicher 23 часа назад | | [–]
Специально для SSH (ssh user@host “команда с аргументами”) я написал эту обходную псевдооболочку, которая позволяет легко и беспрепятственно передавать вектор аргументов в execve.

https://crates.io/crates/arghsh

theamk 21 час назад | | [–]
Обратите внимание, что по крайней мере в Python вместо этого можно использовать «shlex.quote» — он есть в stdlib и не требует дополнительных инструментов.

>>> import subprocess >>> import shlex >>> subprocess.run(['ssh', 'host', shlex.join(['ls', '-la', 'имя файла с пробелами'])]) ls: невозможно получить доступ к 'имя файла с пробелами': Такого файла или каталога нет, работает и во вложенном виде

>>> layer2 = ['ls', '-la', 'имя файла с пробелами'] >>> layer1 = ['ssh', 'host1', shlex.join(layer2)] >>> layer0 = ['ssh', 'host0', shlex.join(layer1)] >>> subprocess.run(layer0) (я не уверен, есть ли эквивалент в Rust, но если нет, то его, вероятно, легко реализовать. Версия на Python состоит всего из нескольких строк)

CGamesPlay 4 часа назад | | | [–]
Неправильно! SSH намного хуже: он использует оболочку входа пользователя , а не sh -c. Так что если оболочка входа пользователя несовместима с POSIX, он все равно не сработает!

>>> subprocess.run([“fish”, “-c”, shlex.join([“echo”, “this isn\'t working”])]) fish: Неожиданный конец строки, кавычки не сбалансированы echo 'this isn'”'”'t working'

eternauta3k 20 часов назад | | | | [–]
Это лишь подтверждает мою привычку переключаться на Python, как только скрипт оболочки достигает любого уровня сложности.
steveklabnik 16 часов назад | | | | [–]
> Я не уверен, есть ли в Rust эквивалент

В стандартной библиотеке нет, но есть пакеты.

endiangroup 22 часа назад | | [–]
AD: Ха! Я только что написал утилиту cmd [1] на этих выходных, чтобы справиться с ограничением ключей ssh для выполнения только команд, которые соответствуют набору правил через `ForceCommand` в `sshd_config` или `Command=””` в `authorized_keys`. Мне любопытно узнать, насколько она восприимчива к вышеупомянутым проблемам, она делегирует ` -c ''` под капотом [2], но есть проверки, чтобы гарантировать, что передается только один аргумент опции команды `–` (для смягчения расширений метасимволов) [3].

Обратите внимание, что этот инструмент предназначен только для обеспечения еще одного уровня безопасности.

[1] https://github.com/endiangroup/cmdjail [2] https://github.com/endiangroup/cmdjail/blob/main/main.go#L30… [3] https://github.com/endiangroup/cmdjail/blob/main/config.go#L…

pabs3 5 часов назад | | [–]
Обратите внимание, что OpenSSH всегда запускает команды в оболочке, и до сих пор они отказались добавлять поддержку exec.

https://bugzilla.mindrot.org/show_bug.cgi?id=2283

blueflow 18 часов назад | | | [–]
В документации сказано, что exec.Command работает с execv напрямую, так что проблем быть не должно? Похоже, вы вообще не обращаетесь к /bin/sh.
1vuio0pswjnm7 20 часов назад | | [–]
“bash, очевидно, для написания скриптов;”

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

Однако Debian и популярные производные от Debian дистрибутивы не используют bash для скриптов, начинающихся с «#!/bin/sh», т. е. «скриптов оболочки».

Интерактивной оболочкой может быть bash, но скриптовая оболочка /bin/sh — это не bash.

https://www.man7.org/linux/man-pages/man1/dash.1.html

https://wiki.ubuntu.com/DashAsBinSh

https://wiki.archlinux.org/title/Dash

https://www.oreilly.com/library/view/shell-scripting-expert/… ^1

https://www.baeldung.com/linux/dash-vs-bash-performance

https://en.wikipedia.org/wiki/Almquist_shell

https://lwn.net/Articles/343924/

https://scriptingosx.com/2020/06/about-bash-zsh-sh-and-dash-… ^2

Я использую оболочку Almquist, а не bash, как для интерактивного использования, так и для написания скриптов. Я часто пишу скрипты интерактивно. Я использую одни и те же скрипты в Linux и BSD. Я восстановил tabcomplete и встроенную функцию fc в dash, чтобы она больше походила на оболочку, из которой она произошла: NetBSD sh.

1. «Это делает его меньше, легче и быстрее, чем bash».

2. «… это явный признак того, что Apple в конечном итоге захочет использовать dash в качестве интерпретатора для скриптов sh».

o11c 19 часов назад | | [–]
«/bin/sh не указывает на bash» — это не то же самое, что «не использует bash для скриптов»

В моей системе имеется 42 скрипта в /bin -> /usr/bin (объединенных), которые начинаются с какого-либо варианта `#! /bin/bash`, и по крайней мере два, которые выполняют `bash -c`, но это не считая неизвестного количества скриптов, которые выглядят немного иначе или находятся в других каталогах.

И имейте в виду, что в Debian почти все программное обеспечение собственной разработки реализовано на Perl, а небольшая часть — на Python.

pabs3 5 часов назад | | [–]
Мой пост в блоге за 2014 год на эту же тему:

https://bonedaddy.net/pabs3/log/2014/02/17/pid-preservation-…

blueflow 22 часа назад | | [–]
Это не страницы руководства неоднозначны, это автор использовал слово “команда”, но, по-видимому, имел ментальную модель этого, как если бы это был вектор аргумента. Команда и вектор аргумента – это разные вещи…
a_t48 22 часа назад | | [–]
Я определенно скатился в кроличью нору, пытаясь/будучи вынужденным исправить такие проблемы. Это начинается с того, что кто-то просто пытается сократить путь, делая небольшой скрипт оболочки в программе Python или что-то в этом роде. Обычно лучший инструмент, который я нашел для исправления этого, это shlex.quote Python – https://docs.python.org/3/library/shlex.html , но YMMV (может потребоваться несколько уровней). Действительно лучшее решение – не выкладывать деньги из своей программы, когда это возможно. 🙂
zahlman 20 часов назад | | [–]
> Нет, давайте просто попробуем (я привел как Python-вызовы, так и простые sh -c-вызовы):

> python2 -c 'import os; os.system(“-x”)' > sh -c -x sh: -c: option required an argument Я не могу воспроизвести это в Python (включая мою локальную сборку 2.7), только используя sh напрямую. Проходя через Python, `sh` правильно сообщает мне, что команда `-x` не найдена.

Но теперь мне интересно: как можно использовать `which` (или `type`, или `file`) для программы с именем `-x`, если она у вас есть?

akovaski 1 час назад | | [–]
> Я не могу воспроизвести это в Python (включая мою локальную сборку 2.7), только используя sh напрямую.

У меня то же самое. Похоже, что POSIX-шники приняли предложение автора в 2022 году, а system() в glibc обновили в 2023 году.

https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=sysdeps…

#include int main(void) { system(“-x”); return 0; } …

> [pid 172293] execve(“/bin/sh”, [“sh”, “-c”, “–“, “-x”], 0x7ffe221d2f58 /* 76 переменных */) = 0

o11c 19 часов назад | | | [–]
Использовать:

command -v — -x В документации POSIX почти для всех команд (включая `command`) говорится: «Утилита command должна соответствовать […] Правилам синтаксиса утилит», которые определяют поведение `–`, даже если это явно не указано.

hackernudes 23 часа назад | | [–]
Я думаю, что это тема, с которой рано или поздно сталкивается каждый пользователь Linux. Это действительно довольно раздражающе.

Мне было трудно следить за статьей, но, возможно, потому, что я уже был знаком с проблемой и просто бегло просматривал ее. Перейдите к разделу “Некоторые эксперименты…” для получения полезных примеров.

Хотя я не согласен с выводом. Я думаю, что должны быть более очевидные способы экранирования ввода, чтобы можно было сохранить рассудок с помощью вложенного вызова 'sh -c'. Может быть, '${var@Q}' и print '%q' достаточно (не могу поверить, что я не знал, что они существуют!)

mrspuratic 21 час назад | | [–]
Давным-давно я администрировал Apache httpd (когда «Apache» означало «httpd»), прежде чем он мог самостоятельно chrootиться. Одной из проблем при ручном chroot'е было то, что конвейерные логи (|rotatelogs) вызывались через «/bin/sh -c». Я написал заглушку «sh», которая допускала только «sh -c command …», которую она передавала в execv(). Просто примитивное разделение аргументов [ t], никаких забавных дел, и в идеале статическая линковка. Также хорошо работало с PHP (например, SquirrelMail, вызывающий, э-э, sendmail).
panzi 23 часа назад | | | [–]
Я знал print '%q', но не ${var@Q}, так что это полезно знать!
degamad 23 часа назад | | [–]
(2021)
kouteiheika 20 часов назад | | [–]
> Стена позора: функция обратных кавычек в Ruby — обеспечивает легкий доступ к system(3);

Он также обеспечивает легкий доступ к экранированию любых аргументов, которые вы хотите передать:

out = `bash -c #{arg.shellescape}` …здесь “arg” всегда будет передаваться как один аргумент.

hello_computer 23 часа назад | [–]
Существует множество нео-оболочек, которые сходят с ума от цветов, автодополнений и SQL-подобных функций, в то время как самые основные проблемы ( вроде обработки новых строк/пробелов/международных символов ) в основном заметаются под ковер с помощью -null/-print0, что является скорее хаком, чем решением. Я думаю, что rc shell Тома Даффа была отличным началом в этом направлении, которое, к сожалению, ни к чему не привело.
chubot 22 часа назад | | [–]
YSH решает проблему «безопасности строк»:

Что такое YSH? https://oils.pub/ysh.html

Сейчас я пишу модуль цитирования, но главное, что это достаточно мощный язык для этого. Он больше похож на Python или JS; вам не нужно прибегать к sed для разбора и цитирования строк.

Я разместил решение quote-argv выше — в YSH оно, скорее всего, будет таким:

var argv = 😐 ls 'arg с пробелом' | # как в bash argv=() ssh example.com $[quote.sh(argv)] Но вы можете написать такую функцию СЕЙЧАС, если хотите

quote.sh следует (тонкой) идиоме замены одинарной кавычки ' на

''', что означает, что он работает на системах с удаленным POSIX sh, а не только YSH!

например, «isn't» в оболочке POSIX указывается как

'isn'''t', которое состоит из трех частей слова:

'isn' ' 't' YSH также имеет:

– JSON, который может правильно обрабатывать каждую строку Unicode, без написания собственных функций синтаксического анализа

– JSON8, дополнительное расширение, которое может выполнять циклический перенос каждой строки байтов, получаемой из ядра Unix.

https://oils.pub/release/latest/doc/j8-notation.html

hello_computer 21 час назад | | | [–]
Мне нравится. Надеюсь, это вызовет интерес.
chubot 20 часов назад | | | [–]
Это также устраняет проблему с eval, которая используется совместно с ssh:

ysh-0.29$ eval ls $dir eval ls $dir ^~~~ [ interactive ]:11: 'eval' требует ровно 1 аргумент И это исправляет оценку слова

YSH не требует везде цитированияhttps://www.oilshell.org/blog/2021/04/simple-word-eval.html

https://oils.pub/release/latest/doc/simple-word-eval.html

o11c 22 часа назад | | [–]
Справедливости ради, большинство этих «базовых проблем» имеют базовые решения, если только вы не пытаетесь избегать инструментов GNU.

Самый неприятный случай, вероятно, `globasciiranges`.


Рассмотрите возможность подачи заявки на набор в YC на осень 2025 года! Заявки принимаются до 4 августа

Source: news.ycombinator.com

Leave a Reply

Your email address will not be published. Required fields are marked *