Цикл for не нужен. Попробуйте это:
mkdir `echo file{001..512}`
Как указано в комментариях:
There is no need for command substitution and echo.
Итак,Brace Expansionдостаточно для выполнения задачи:
mkdir file{001..512}
tl;dr :в какой-то момент yes
будет заблокирована запись, если данные не читаются на другой стороне. Он не сможет продолжать выполнение до тех пор, пока эти данные не будут прочитаны или не будет получен сигнал, поэтому обычно вам не нужно yes
беспокоиться о записи гигабайтов и гигабайтов данных.
Важно помнить, что канал представляет собой структуру данных FIFO, а не просто чистый поток, который отбрасывает данные, если они не были немедленно прочитаны получателем. То есть, хотя в большинстве случаев может показаться, что это непрерывный поток данных от записывающего приложения к приложению для чтения, для этого требуется промежуточное хранилище, и это промежуточное хранилище имеет конечный размер.*
Если мы посмотрим на канал (7 )справочную страницу , мы можем прочитать следующее о размере этого внутреннего буфера (добавлено выделение):
In Linux versions before 2.6.11, the capacity of a pipe was the same as the system page size (e.g., 4096 bytes on i386). Since Linux 2.6.11, the pipe capacity is 16 pages (i.e., 65,536 bytes in a system with a page size of 4096 bytes). Since Linux 2.6.35, the default pipe capacity is 16 pages, but the capacity can be queried and set using the fcntl(2) F_GETPIPE_SZ and F_SETPIPE_SZ operations.
Предполагая, что вы используете стандартную систему x86 _64, весьма вероятно, что вы используете страницы размером 4 КБ, поэтому верхний предел емкости канала 2^16, вероятно, является правильным, если ни одна из сторон конвейера в какой-то момент не использовала fcntl(F_SETPIPE_SZ)
. В любом случае принцип остается :промежуточным хранилищем между двумя сторонами трубы конечным и хранится в памяти.
В абстрактном конвейере a | b
это хранилище используется в период между a
записью некоторых данных и b
их фактическим чтением. Предполагая, что ваш make
вызов (и любые дочерние элементы, также связанные с этим каналом путем наследования ), на самом деле не пытаются читать стандартный ввод или делают это очень редко, системный вызов write
из yes
в конечном итоге просто не выйдет yes
из спящего режима, когда пространство в буфере будет исчерпано. Затем yes
будет ожидать пробуждения, либо когда буфер снова станет доступным, либо когда будет получен сигнал. **Все это обрабатывается планировщиком процессов ядра. Вы можете увидеть это в pipe_write()
,который является обработчиком write()
для каналов:
static ssize_t
pipe_write(struct kiocb *iocb, struct iov_iter *from)
{
/*... */
if (pipe_full(pipe->head, pipe->tail, pipe->max_usage))
wake_next_writer = false;
if (wake_next_writer)
wake_up_interruptible_sync_poll(&pipe->wr_wait, EPOLLOUT | EPOLLWRNORM);
/*... */
}
Когда сторона make
в конце концов завершается, yes
будет отправлено SIGPIPE
в результате записи в канал, когда на другом конце ничего не осталось. Затем он — в зависимости от реализации yes
— вызовет либо свой собственный обработчик сигналов, либо обработчик сигналов ядра по умолчанию, и завершится.***
*В простых случаях, когда получатель обрабатывает данные примерно с той же скоростью, с которой они записываются, эта передача также может быть нулевой -копией без промежуточного буфера с использованием виртуальной памяти для сопоставления и предоставления доступа к физической странице. из процесса записи, доступного получателю. Однако в случае, который вы описываете, в конечном итоге потребуется использовать конвейерный буфер для хранения непрочитанных данных.
**Также возможно, что запись выполняется с установленным флагом O_NONBLOCK
в файловом дескрипторе, который включает неблокирующий режим -. В этом случае вы, вероятно, получите одну незавершенную запись, а затем запись вернет EAGAIN
, и приложение должно будет справиться с этим самостоятельно. Скорее всего, он сделает это, приостановив или запустив какой-либо другой код по своему выбору для обработки переполнения канала. В случае каждой современной версии yes
, которую я могу найти, и большинства других приложений, описание выше — это то, что происходит, поскольку они не используют O_NONBLOCK
.
***Приложение может делать все, что захочет, после полученияSIGPIPE
--оно может даже теоретически принять решение не завершаться. Однако все распространенные yes
используют обработчик SIGPIPE
по умолчанию, который просто завершает работу без выполнения каких-либо дальнейших инструкций пользовательского пространства.