Почему argv включает имя программы?

Используйте Python и его модуль CSV, например, следующую единственную команду:

python -c 'import sys,csv
w = csv.writer(sys.stdout, quoting=csv.QUOTE_NONNUMERIC)
for row in csv.reader(sys.stdin):
    del row[3]
    w.writerow(row)' < file.csv > file_edited.csv

Волшебство происходит в предпоследней строке команды. В Python массивы начинаются с индекса 0, поэтому row [3] является четвертым столбцом; Итак, этот просто удаляет четвертый столбец в каждой записи.

Кроме того, вы можете просто напечатать столбцы 0, 1, 2, 4 и 5, используя

python -c 'import sys,csv
w = csv.writer(sys.stdout, quoting=csv.QUOTE_NONNUMERIC)
for row in csv.reader(sys.stdin):
    w.writerow([row[0], row[1], row[2], row[4], row[5]])' < file.csv > file_edited.csv
107
12.10.2016, 08:20
5 ответов

Для начала обратите внимание, что argv [0] не обязательно является именем программы. Это то, что вызывающий помещает в argv [0] системного вызова execve (например, см. этот вопрос о переполнении стека ). (Все другие варианты exec не являются системными вызовами, а являются интерфейсами для execve .)

Предположим, например, следующее (с использованием execl ):

execl("/var/tmp/mybackdoor", "top", NULL);

/ var / tmp / mybackdoor - это то, что выполняется, но для argv [0] установлено значение top , и это то, что ps или ( реальный) верх будет отображаться. См. этот ответ на U&L SE для получения дополнительной информации.

Если отбросить все это в сторону: до появления таких фантастических файловых систем, как / proc , argv [0] был единственным способом для процесса узнать свое собственное имя. Для чего это было бы хорошо?

  • Некоторые программы настраивают свое поведение в зависимости от имени, по которому они были вызваны (обычно с помощью символьных или жестких ссылок, например Утилиты BusyBox ; еще несколько примеров приведены в других ответы на этот вопрос).
  • Более того, службы, демоны и другие программы, которые регистрируются через системный журнал, часто добавляют свое имя к записям журнала; без этого отслеживание событий стало бы практически невозможным.
131
27.01.2020, 19:29

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

И есть довольно много программ, которые ведут себя по-разному в зависимости от того, какое имя используется для их вызова, так что вы можете просто создавать разные ссылки на них и получать разные «команды». Самый экстремальный пример, который я могу придумать, - это busybox , который действует как несколько десятков различных «команд» в зависимости от того, как он называется .

Правка : Ссылки на 1-е издание Unix, в соответствии с запросом

Можно увидеть, например,из main функции cc , что уже использовались argc и argv . Оболочка копирует аргументы в parbuf внутри части цикла newarg , обрабатывая при этом саму команду так же, как и аргументы. (Конечно, позже он выполняет только первый аргумент, который является именем команды). Похоже, execv и родственников тогда не существовало.

37
27.01.2020, 19:29

Путь к программе - argv [0] , чтобы программа могла извлекать файлы конфигурации и т. Д. Из своего установочного каталога.
Это было бы невозможно без argv [0] .

1
27.01.2020, 19:29

Еще одним примером применения этой программы является эта программа, которая заменяет себя ... самой собой, пока вы не наберете что-то, что не y .

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char** argv) {

  (void) argc;

  printf("arg: %s\n", argv[1]);
  int count = atoi(argv[1]);

  if ( getchar() == 'y' ) {

    ++count;

    char buf[20];
    sprintf(buf, "%d", count);

    char* newargv[3];
    newargv[0] = argv[0];
    newargv[1] = buf;
    newargv[2] = NULL;

    execve(argv[0], newargv, NULL);
  }

  return count;
}

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

Пример:

$ ./res 1
arg: 1
y
arg: 2
y
arg: 3
y
arg: 4
y
arg: 5
y
arg: 6
y
arg: 7
n

7 | $

Источник и дополнительная информация .

3
27.01.2020, 19:29

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

Из ccache man page: "Есть два способа использования ccache. Вы можете префикснуть команды компиляции с помощью ccache или позволить ccache маскироваться под компилятор, создав символическую ссылку (с именем компилятора) на ccache. Первый способ наиболее удобен, если вы только хотите опробовать ccache или хотите использовать его для некоторых конкретных проектов. Второй метод наиболее полезен, когда вы хотите использовать ccache для всех ваших компиляций."

Метод симлинков включает выполнение следующих команд:

cp ccache /usr/local/bin/
ln -s ccache /usr/local/bin/gcc
ln -s ccache /usr/local/bin/g++
ln -s ccache /usr/local/bin/cc
ln -s ccache /usr/local/bin/c++
... etc ...

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

1
27.01.2020, 19:29

Теги

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