Какие оболочки (если есть) избегают чтения heredocs в память сразу?

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

Во-первых, вам нужно получить список запущенных процессов. Чтобы перечислить запущенные процессы, используйте ps .Вы, вероятно, уже знаете это, но это хорошее место для начала. Вы видели такие команды, как ps ax , что означало бы перечислить все ( a ), даже те, у которых нет связанного tty ( x ).

Теперь необходимо указать ему выбрать все процессы ( a ) и отобразить имена исполняемых файлов ( c ). Вы можете включить x или нет: любой интерактивный bash обязательно будет иметь связанный tty, но сценарий оболочки может не включать его, поэтому включать его зависит от того, что вам нужно. Чтобы упростить синтаксический анализ его вывода, также удобно ограничить его вывод интересующими нас значениями, а именно пользователем и командой ( o user, command ).

Это дает следующее:

$ ps aco user,command
root   login
root   bash
user   bash
root   bash
user   lynx
...

Теперь вам нужно отфильтровать его, чтобы найти экземпляры bash для каждого пользователя. Для этого вы можете передать его по конвейеру awk , используя скрипт $ 2 == "bash" {print $ 1} , что означает, что "если второй столбец -" bash ", напечатайте первый столбец ».

$ ps aco user,command | awk '$2=="bash" {print $1}'
root
user
root

Наконец, вы хотите отсортировать вывод и удалить дубликаты, используя sort и uniq .

$ ps aco user,command | awk '$2=="bash" {print $1}' | sort | uniq
root
user

Если вам нужно количество пользователей, запускающих 'bash', вы можете просто подсчитать строки в выводе этого:

$ ps aco user,command | awk '$2=="bash" {print $1}' | sort | uniq | wc -l
2

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

3
26.03.2017, 00:53
1 ответ

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

Экспериментально в Debian jessie, dash, bash, mksh и zsh загружают здесь документ размером 130 КБ в память, тогда как ksh93 копирует фрагменты размером 64 КБ без выделения дополнительной памяти. Таким образом, единственный способ использовать здесь документ, который не помещается в памяти, - это убедиться, что ваш скрипт выполняется с помощью ksh93 (или, возможно, ksh88) - и перед этим убедитесь, что это так и с другими версиями, я не знаю Не проверил, что поведение одинаково для всех сборок ksh.

Что вы можете сделать более переносимым, так это поместить все данные в конец сценария и использовать tail -c $ offset для извлечения полезной нагрузки. На практике это работает, потому что ни одна из обычных оболочек не загружает сценарий полностью в память перед его выполнением.Преимущество этого метода в том, что полезная нагрузка может быть двоичной - здесь документы не могут содержать строку конца heredoc или нулевые байты.

Если ваш скрипт постоянный, вы можете жестко запрограммировать смещение полезной нагрузки. Если это не так, вы можете поместить выделенный маркер в конец сценария и использовать awk для определения его местоположения:

offset=$(awk '{offset += length($0) + 1}
              $0 == "# payload starts here (do not remove this magic comment)" {
                  print offset; exit
              }')
…
tail -c "$offset" <"$0" — …
…
# payload starts here (do not remove this magic comment)

Если у вас более одной полезной нагрузки, вам понадобится более сложная команда для их извлечения. Помните, что head -c существует не во всех вариантах unix. Вы можете использовать dd ibs = 1 count = $ bytes для достижения того же эффекта, но это может быть очень медленным, поскольку многие реализации dd будут копировать по одному байту за раз. Я бы порекомендовал добавить tar-архив и извлекать из него файлы по имени.

4
27.01.2020, 21:18

Теги

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