Может ли программа получить количество пробелов между аргументами командной строки в POSIX?

rsync обычно создает новую версию файла рядом с местом назначения, а затем переключает ее на имя назначения в последний момент, когда оно будет завершено. Новая версия может быть создана либо с использованием дельт, то есть изменений между источником и местом назначения, либо как полная копия. (См. Мой ответ для Более умная передача файлов, чем rsync? , чтобы прояснить это различие.)

Флаг - partial сообщает rsync о необходимости сохранения и использования любой частично переданный файл в качестве целевого, если соединение прервано по какой-либо причине. (В противном случае частично переданный файл отбрасывается.) Преимущество этого флага состоит в том, что время и полоса пропускания, потраченные на передачу файла, не тратятся впустую, когда rsync прерывается и повторяется. Недостатком этого флага является то, что файл, переданный на 90% до прерывания, может быть заменен тем же файлом, переданным только на 10% до прерывания.

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

23
15.03.2018, 08:10
6 ответов

Бессмысленно говорить о «промежутках между аргументами»; это концепция оболочки.

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

Существуют и другие способы создания вектора строк. Многие программы разветвляют и выполняют свои собственные подпроцессы -с предопределенными вызовами команд -, и в этом случае никогда не существует такой вещи, как "командная строка". Точно так же графическая оболочка (рабочего стола )может запустить процесс, когда пользователь снова перетащит значок файла и поместит его на командный виджет -, нет текстовой строки для символов «между» аргументами.

Что касается вызванной команды, то, что происходит в оболочке или другом родительском/предшественнике процессе, является частным и скрытым -мы видим только массив строк, который стандарт C указывает, что main()может принять.

39
27.01.2020, 19:41

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

58
27.01.2020, 19:41

Нет, это невозможно, если пробелы не являются частью аргумента.

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

Все команды в Unix в конечном итоге выполняются одной из exec()семейства функций. Они принимают имя команды и список или массив аргументов. Ни один из них не принимает командную строку так, как она введена в приглашении оболочки. Функция system()делает это, но ее строковый аргумент позже выполняется функцией execve(), которая, опять же, принимает массив аргументов, а не строку командной строки.

16
27.01.2020, 19:41

В общем, это невозможно, как объяснялось в нескольких других ответах.

Однако оболочки Unix являются обычными программами (, и они интерпретируют командную строку и подставляют ее, то есть расширяют команду перед выполнением forkи execveдля нее ). См. это объяснение bashопераций оболочки . Вы можете написать свою собственную оболочку(или исправить некоторые существующие свободные программы , например. GNU bash)и использовать его в качестве оболочки (или даже оболочки входа в систему, см. passwd (5)и оболочки (5)).

Например, у вас может быть ваша собственная программа-оболочка, поместившая полную командную строку в какую-нибудь переменную окружения (представьте себе MY_COMMAND_LINEнапример)-или используйте любой другой вид inter -связь процесса для передачи командной строки из оболочки в дочерний процесс -.

Я не понимаю, зачем вам это нужно, но вы можете запрограммировать оболочку, ведущую себя таким образом (, но я не рекомендую этого делать ).

Кстати, программа может быть запущена некоторой программой, которая не оболочка (, но которая выполняет fork (2 ), затем execve (2 ),или просто execveдля запуска программы в ее текущем процессе ). В таком случае вообще нет командной строки, и ваша программа может быть запущена без команды...

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

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

9
27.01.2020, 19:41

Я просто добавлю то, чего не хватает в других ответах.

Нет

См. другие ответы

Может быть, вроде

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

Вам нужно использовать кавычки. Поэтому вместо

./myprog      aaa      bbb

вам нужно сделать одно из этих

./myprog "     aaa      bbb"
./myprog '     aaa      bbb'

Это передаст программе один аргумент со всеми пробелами. Между ними есть разница: второй буквальный, точно такая же строка, как она выглядит (, за исключением того, что 'нужно набирать как\'). Первый интерпретирует некоторые символы, но разделяется на несколько аргументов. См. цитирование оболочки для получения дополнительной информации. Так что не надо переписывать оболочку, конструкторы оболочки уже об этом подумали. Однако, поскольку теперь это один аргумент, вам придется делать больше передач внутри программы.

Вариант 2

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

./myprog << EOF
    aaa      bbb
EOF

или

./myprog
Tell me what you want to tell me:
aaaa bbb
ctrl-d

(Курсивом выводится программа)

0
27.01.2020, 19:41

Вы всегда можете указать своей оболочке сообщать приложениям, какой код оболочки приводит к их выполнению. Например, с zsh, передавая эту информацию в переменной окружения $SHELL_CODEс использованием хука preexec()(printenv, используемого в качестве примера, вы должны использовать getenv("SHELL_CODE")в своей программе):

$ preexec() export SHELL_CODE=$1
$ printenv SHELL_CODE
printenv SHELL_CODE
$ printenv  SHELL_CODE
printenv  CODE
$ $(echo printenv SHELL_CODE)
$(echo printenv SHELL_CODE)
$ for i in SHELL_CODE; do printenv "$i"; done
for i in SHELL_CODE; do printenv "$i"; done
$ printenv SHELL_CODE; : other command
printenv SHELL_CODE; : other command
$ f() printenv SHELL_CODE
$ f
f

Все они будут выполнять printenvкак:

execve("/usr/bin/printenv", ["printenv", "SHELL_CODE"], 
       ["PATH=...",..., "SHELL_CODE=..."]);

Разрешение printenvизвлекать код zsh, который приводит к выполнению printenvс этими аргументами. Что вы хотите сделать с этой информацией, мне не ясно.

С bashфункция, наиболее близкая к zshpreexec(), будет использовать его $BASH_COMMANDв ловушке DEBUG, но обратите внимание, что bashвыполняет некоторый уровень перезаписи в этом (и, в частности, реорганизованы некоторые пробелы, используемые в качестве разделителя ), и это применяется к каждому (, ну, некоторые команды ), а не вся командная строка, введенная в приглашении (, см. также functraceопция ).

$ trap 'export SHELL_CODE="$BASH_COMMAND"' DEBUG
$ printenv SHELL_CODE
printenv SHELL_CODE
$ printenv $(echo 'SHELL_CODE')
printenv $(echo 'SHELL_CODE')
$ for i in SHELL_CODE; do printenv "$i"; done; : other command
printenv "$i"
$ printf '%s\n' "$(printenv "SHELL_CODE")"
printf '%s\n' "$(printenv "SHELL_CODE")"
$ set -o functrace
$ printf '%s\n' "$(printenv "SHELL_CODE")"
printenv "SHELL_CODE"
$ print${-+env  }    $(echo     'SHELL_CODE')
print${-+env  } $(echo     'SHELL_CODE')

Посмотрите, как некоторые из пробелов, которые являются разделителями в синтаксисе языка оболочки, были сжаты до 1 и как не всегда полная командная строка передается команде. Так что, вероятно, не полезно в вашем случае.

Обратите внимание, что я бы не советовал делать подобные вещи, так как вы потенциально передаете конфиденциальную информацию каждой команде, как в:

echo very_secret | wc -c | untrustedcmd

передаст этот секрет как wc, так и untrustedcmd.

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

.
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#define WRAP(x) (setenv("C_CODE", #x, 1), x)

int main(int argc, char *argv[])
{
  if (!fork()) WRAP(execlp("printenv", "printenv", "C_CODE", NULL));
  wait(NULL);
  if (!fork()) WRAP(0 + execlp("printenv",   "printenv", "C_CODE", NULL));
  wait(NULL);
  if (argc > 1 && !fork()) WRAP(execvp(argv[1], &argv[1]));
  wait(NULL);
  return 0;
}

Пример:

$./a.out printenv C_CODE
execlp("printenv", "printenv", "C_CODE", NULL)
0 + execlp("printenv", "printenv", "C_CODE", NULL)
execvp(argv[1], &argv[1])

Посмотрите, как некоторые пробелы были сжаты процессором C pre -, как в случае с bash. В большинстве, если не во всех языках, объем пространства, используемого в разделителях, не имеет значения, поэтому неудивительно, что компилятор/интерпретатор допускает здесь некоторую вольность с ними.

3
27.01.2020, 19:41

Теги

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