Bash :Выполнить команду в каждом каталоге с файлом my _suites.cfg?

Ладно, переходим к исходному коду!

Программа

util-linuxпользователя loginуже занята к моменту появления приглашения для входа в систему. Начнем там , точнее в файле login-utils/login.c.

Теперь loginотвечает за подсказку login, поскольку она генерируется вloginpam_get_promptи регистрируется в PAM вinit_loginpam. Затем функцияloginpam_authвступает во владение, и управление переходит к функцииpam_authenticatePAM. Это означает, что loginпросто определяет подсказку для имени пользователя и все.

Для PAM тогда :то, что нас интересует, явно происходит вpam_authenticate:

The pam_authenticate function is used to authenticate the user. The user is required to provide an authentication token depending upon the authentication service, usually this is a password, but could also be a finger print.

Теперь теневая -аутентификация (/etc/passwd,/etc/shadow)обрабатывается модулем pam_unix. Мой дистрибутив (Arch )предоставляет PAM через пакет pam, что означает, что наше путешествие продолжается к linux -pam.org и его исходному коду .modules/pam_unix/pam_unix_auth.cкажется хорошим местом для начала. Модули PAM предоставляют свой механизм аутентификации через функцию pam_sm_authenticate, которую мы находим здесь . Пароль (или «токен аутентификации», см. выше ), извлекается с помощью вызова функции PAM pam_get_authtok. Он объявлен в заголовочном файле security/pam_ext.h, так что мы идем дальше.

extern int PAM_NONNULL((1,3)) 
pam_get_authtok (pam_handle_t *pamh, 
                 int item, 
                 const char **authtok, 
                 const char *prompt);

В этих рассуждениях нет ничего многообещающего, но хорошо... Давайте посмотрим определение . pam_unixпередал NULLвместо аргумента promptи PAM_AUTHTOKвместо item, так что мы получаем здесь . Теперь этот жестко закодированный PAM_PROMPT_ECHO_OFF, переданный pam_prompt, просто не выглядит хорошо для меня...

retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0], "%s", PROMPT);

Кстати, пароль PROMPTтакже жестко запрограммирован(здесь ), так что моя мечта о более экзотическом запросе пароля исчезает... Впрочем, давайте перейдем к функции pam_prompt. Фактическое приглашение происходит здесь , где PAM вызывает функцию диалога, выбранную несколькими строками выше . Беглый взгляд на функции pam_get_itemиpam_set_itemзнакомит нас со структурой pam_conv, определенной здесь .

Теперь найти информацию о функции диалога PAM по умолчанию было намного сложнее, чем следовало бы (Я думаю ). Куда бы я ни посмотрел, структура оставалась неинициализированной и pam_unix, похоже, не определяет свою собственную. Однако мне удалось найти общую функцию misc_conv, которая передает PAM_PROMPT_ECHO_OFFнаread_stringи... здесь , где PAM деактивирует входную обратную связь.

Заключение:отсутствие обратной связи по паролю жестко запрограммировано. Очень жаль. Немного покопавшись, я нашел эту проблему на GitHub и эту ветку Arch BBS . Судя по всему, эта функция была доступна еще тогда, когда PAM не был стандартом для аутентификации. Я предполагаю, что имеет смысл не реализовывать это снова -безопасность и все -, но вы знаете, вариант был бы хорош.

В общем, я только что заказал себе новую клавиатуру.

1
09.03.2021, 16:38
3 ответа

Поскольку в вашем теге указано bash, вы можете использовать опцию globstar:

shopt -s globstar
for d in **/; do if [[ -f "$d/my_suites.cfg" ]]; then cd "$d"; make; cd -; fi; done

Это будет перебирать все каталоги и подкаталоги -текущего каталога, проверять, существует ли файл my_suites.cfg, и если да, переходить в этот каталог, вызывать makeи возвращаться в исходный каталог..

1
18.03.2021, 22:26

Вы можете использовать findдля выполнения команды (пример :pwd )с рабочим каталогом, в котором найден именованный файл:

find /path/to/repository -type f -name my_suites.cfg -execdir pwd \;

/path/to/repository также может быть относительным путем (даже ".")

1
18.03.2021, 22:26

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

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

TL;DR(Слишком длинно, не читал)

Если не имеет значения, что самые новые файлы еще не распознаны:

$ mlocate --basename --regex "^my_suites.cfg$" \
| xargs dirname \
| xargs -d '\n' <command-to-run-on-the-file>

В противном случае, если эффективность не так важна, (предполагая, что мы ищем рекурсивно только в домашнем каталоге(~):

$ find ~ -name "my_suites.cfg" -type f \
| xargs dirname \
| xargs -d '\n' <command-to-run-on-the-file>

Полная версия

Поиск файлов

Если искомые файлы разбросаны по всей системе, должен заботиться об эффективности.

Быстрый (э )способ

С некоторыми недостатками

$ mlocate --basename --regex "^my_suites.cfg$"
  • mlocateищет пути к файлам в базе данных, которая обновляется один раз в день для большинство дистрибутивов. Таким образом, он может не распознать недавно созданные или недавно переехал файлы. Но поскольку он просматривает базу данных вместо того, чтобы просматривать сама файловая система, ее поиск очень эффективен.
  • Параметр --basenameуказывает, что мы ищем прямой название файл, не включая путь/каталоги к нему.
  • Параметр --regexразрешает использование регулярных выражений в поиск шаблон. (^ожидает, что строка начнется здесь, а $ожидает строка, чтобы закончить там.)

Способ «всегда от -до -даты»

$ find / -name "my_suites.cfg" -type f
  • findпросматривает практически каждую папку, которую может найти, и перечисляет каждый файл с именем _suites.cfg. Из-за этого многие чтение -операций, которые он должен выполнить, тем больше папок он ищет тем медленнее он становится.
  • Параметр -nameуказывает, что мой _suites.cfg — это имя файл, вместо т.е. папки, в которой находится искомый нами файл.
  • Опция -typeуказывает, что мы ищем файл , а не для каталог, символическая ссылка, сокет или что-то в этом роде.

Запуск пользовательской команды для каждого из файлов

... вот что значит xargsдля

Простой пример

$ echo "some simple example" | xargs mkdir
$ # now there are three directories, named by the echoed words
$ ls
example  simple  some

Что-то более сложное:

$ echo "hello world" | xargs -d ' ' -I % echo 'Print a word: %'
Print a word: hello
Print a word: world

  • -dопция :указывает, какой символ отделяет аргументы от каждого другое (здесь :пробел ).
  • -Iопция :Все вхождения данного символа(%в этом примере )будет заменен аргументом, пришедшим из канала (до|)

Вот что происходит в приведенном выше примере:

  1. echoвыводит «hello world» на стандартный вывод (stdout).
  2. Канал(|)передает это значение ("hello world" )следующей команде: который оказывается xargs.
  3. xargsищет вхождения разделителя в аргументе и расколы аргумент, в котором он находит разделитель.
  4. xargsперебирает только что созданные аргументы и запускает команду со значением аргумента вместо%

Дополнительная информация

0
18.03.2021, 22:26

Теги

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