Скажите, если я написал программу со следующей строкой:
int main(int argc, char** argv)
Теперь он знает, какие аргументы командной строки передаются ему, проверяя содержимое argv
.
Может ли программа определить, сколько пробелов между аргументами? Например, когда я набираю их в bash:
ibug@linux:~ $ ./myprog aaa bbb
ibug@linux:~ $ ./myprog aaa bbb
Среда - это современный Linux (например, Ubuntu 16.04), но я полагаю, что ответ должен относиться к любым POSIX-совместимым системам.
Ответы:
Не имеет смысла говорить о «пробелах между аргументами»; это концепция оболочки.
Работа оболочки состоит в том, чтобы взять целые строки ввода и сформировать их в массивы аргументов для запуска команд. Это может включать анализ строк в кавычках, расширение переменных, подстановочные знаки файлов и выражения тильды и многое другое. Команда запускается стандартным
exec
системным вызовом, который принимает вектор строк.Существуют и другие способы создания вектора строк. Многие программы разрабатывают и выполняют свои собственные подпроцессы с предопределенными вызовами команд - в этом случае никогда не бывает такой вещи, как «командная строка». Точно так же графическая оболочка (на рабочем столе) может запустить процесс, когда пользователь перетаскивает значок файла и помещает его в командный виджет - опять же, нет текстовой строки, в которой бы были символы между аргументами.
Что касается вызываемой команды, то, что происходит в оболочке или другом родительском / предшественнике, является частным и скрытым - мы видим только тот массив строк, который стандарт C определяет, который
main()
может принять.источник
tar cf texts.tar *.txt
то программа tar получит два аргумента и*.txt
сама должна развернуть второй ( ). Многие люди не понимают, как это действительно работает, пока не начнут писать свои собственные скрипты / программы, которые обрабатывают аргументы.В общем нет. Разбор командной строки выполняется оболочкой, которая не делает непарсированную строку доступной для вызываемой программы. Фактически, ваша программа может выполняться из другой программы, которая создала argv не путем разбора строки, а путем программного создания массива аргументов.
источник
execve(2)
.Нет, это невозможно, если только пробелы не являются частью аргумента.
Команда обращается к отдельным аргументам из массива (в той или иной форме в зависимости от языка программирования), и фактическая командная строка может быть сохранена в файле истории (если она введена в интерактивном режиме в оболочке, имеющей файлы истории), но никогда не передается команде в любой форме.
Все команды в Unix в конце выполняются одной
exec()
из функций семейства. Они принимают имя команды и список или массив аргументов. Ни один из них не использует командную строку, введенную в командной строке.system()
Функция делает, но его аргументы строки позже выполняютсяexecve()
, что, опять - таки, принимает массив аргументов , а не строка командной строки.источник
hello
иworld
является буквально пробелами между двумя аргументами.hello
иworld
в буквальном смысле подача второго из трех аргументов.В общем, это невозможно, как объяснили несколько других ответов.
Тем не менее, оболочки Unix являются обычными программами (и они интерпретируют командную строку и ее глобализацию , то есть расширяют команду перед выполнением
fork
&execve
для нее). Смотрите это объяснение обbash
операциях с оболочкой . Вы можете написать свою собственную оболочку (или вы можете исправить какую-то существующую оболочку свободного программного обеспечения , например GNU bash ) и использовать ее в качестве оболочки (или даже оболочки для входа в систему, см. Passwd (5) & shells (5) ).Например, ваша собственная программа оболочки может поместить полную командную строку в некоторую переменную среды (представьте,
MY_COMMAND_LINE
например) - или использовать любой другой тип межпроцессного взаимодействия для передачи командной строки из оболочки в дочерний процесс-.Я не понимаю, почему вы хотели бы сделать это, но вы могли бы кодировать оболочку, которая ведет себя таким образом (но я рекомендую не делать этого).
Кстати, программа может быть запущена некоторой программой, которая не является оболочкой (но которая выполняет fork (2), а затем execve (2) , или просто
execve
для запуска программы в текущем процессе). В этом случае вообще нет командной строки, и ваша программа может быть запущена без команды ...Обратите внимание, что у вас может быть какая-то (специализированная) система Linux без какой-либо установленной оболочки. Это странно и необычно, но возможно. Затем вам нужно будет написать специализированную программу инициализации, запускающую другие программы по мере необходимости - без использования какой-либо оболочки, но с помощью
fork
&execve
системных вызовов.Читайте также Операционные системы: три простых части, и не забывайте, что
execve
это практически всегда системный вызов (в Linux они перечислены в syscalls (2) , см. Также intro (2) ), которые повторно инициализируют виртуальное адресное пространство (и некоторые другие вещи) процесса, делающего это.источник
argv[0]
имя программы и остальные элементы аргументов являются спецификациями POSIX и не могут быть изменены. Среда выполнения может указыватьargv[-1]
для командной строки, я полагаю ...execve
документацию. Вы не можете использоватьargv[-1]
, это неопределенное поведение, чтобы использовать его.execvepluscmd
функцию с дополнительным параметром (или соглашением argv), системный вызов создает вектор аргумента для main, который содержит указатель на командную строку перед указателем на имя программы, а затем передает адрес указателя на имя программы, какargv
при вызове программыmain
...sh
. Так что не нова.Вы всегда можете указать своей оболочке сообщить приложениям, какой код оболочки приводит к их выполнению. Например, с
zsh
помощью передачи этой информации в$SHELL_CODE
переменную окружения с помощьюpreexec()
ловушки (printenv
используется в качестве примера, вы будете использоватьgetenv("SHELL_CODE")
в своей программе):Все они будут выполнены
printenv
как:Позволяет
printenv
получить код zsh, который приводит к выполнениюprintenv
с этими аргументами. Что бы вы хотели сделать с этой информацией, мне неясно.С
bash
помощью функции, ближайшей кzsh
'spreexec()
, будет использовать ее$BASH_COMMAND
вDEBUG
ловушке, но обратите внимание, что в этомbash
есть некоторый уровень переписывания (и, в частности, рефакторинг некоторых пробельных символов, используемых в качестве разделителя), и это применяется к каждой (ну, некоторым) команде запустить, а не всю командную строку, как указано в приглашении (см. такжеfunctrace
параметр).Посмотрите, как некоторые из пробелов, которые являются разделителями в синтаксисе языка оболочки, были сжаты в 1 и как не вся командная строка не всегда передается команде. Так что, вероятно, не полезно в вашем случае.
Обратите внимание, что я бы не советовал делать такие вещи, так как вы потенциально можете передавать конфиденциальную информацию каждой команде, как в:
просочится эту тайну как
wc
иuntrustedcmd
.Конечно, вы могли бы делать такие вещи для других языков, кроме оболочки. Например, в C вы можете использовать некоторые макросы, которые экспортируют код C, который выполняет команду в среду:
Пример:
Посмотрите, как некоторые пробелы были сжаты препроцессором C, как в случае bash. В большинстве, если не во всех языках, объем пространства, используемого в разделителях, не имеет значения, поэтому не удивительно, что компилятор / интерпретатор берет на себя некоторую свободу здесь.
источник
BASH_COMMAND
он не содержал исходных пробелов, разделяющих аргументы, поэтому его нельзя было использовать для буквального запроса OP. Включает ли этот ответ какую-либо демонстрацию в любом случае для этого конкретного варианта использования?Я просто добавлю то, чего не хватает в других ответах.
нет
Смотрите другие ответы
Может быть, вроде
В программе ничего нельзя сделать, но есть что-то, что можно сделать в оболочке при запуске программы.
Вам нужно использовать кавычки. Так что вместо
вам нужно сделать один из этих
Это передаст в программу один аргумент со всеми пробелами. Между ними есть различие, второе буквальное, в точности такая строка, как кажется (за исключением того, что
'
должно быть напечатано как\'
). Первый будет интерпретировать некоторые символы, но будет разбит на несколько аргументов. См. Цитирование оболочки для получения дополнительной информации. Поэтому не нужно переписывать оболочку, дизайнеры оболочки уже подумали об этом. Однако, поскольку теперь это один аргумент, вам придется больше проходить внутри программы.Вариант 2
Передайте данные через стандартный ввод. Это нормальный способ получить большие объемы данных в команду. например
или
./myprog
Tell me what you want to tell me:
aaaa bbb
ctrl-d
(Курсив - вывод программы)
источник
./myprog␣"␣␣␣␣␣aaa␣␣␣␣␣␣bbb"
выполняет (обычно в дочернем процессе) файл, хранящийся в нем,./myprog
и передает ему два аргумента:./myprog
и␣␣␣␣␣aaa␣␣␣␣␣␣bbb
(argv[0]
иargc[1]
,argc
будучи равным 2), и, как и в OP, пространство, разделяющее эти два аргумента, никоим образом не передается кmyprog
.