Использование раскрытия параметров для генерации списка аргументов для `mkdir -p`

10

У меня есть что-то вроде этого:

% ls -1dF /tmp/foo/*
/tmp/foo/000f9e956feab3ee4625aebb65ae7bae9533cdbc/
/tmp/foo/002e34c2218f2c86fefd2876f0e5c2559c5fb3c4/
/tmp/foo/00b483576791bab751e6cb7ee0a7143af43a8069/
.
.
.
/tmp/foo/fedd0f7b545e7ae9600142656756456bc16874d3/
/tmp/foo/ff51ac87609012137cfcb02f36624f81cdc10788/
/tmp/foo/ff8b983a7411395344cad64182cb17e7cdefa55e/

Я хочу создать каталог barв каждом из подкаталогов foo.

Если я попытаюсь сделать это с

% mkdir -p /tmp/foo/*/bar

... я получаю ошибку

zsh: no matches found: /tmp/foo/*/bar

(Оглядываясь назад, я могу понять причину ошибки.)

Я знаю, что могу решить исходную проблему с помощью цикла for, но мне любопытно узнать, zshподдерживает ли какая-либо форма раскрытия параметров, которая выдает желаемый аргумент для одного вызова mkdir -p. IOW, расширение параметра эквивалентно «добавлению /barк каждому префиксу, сгенерированному расширением /tmp/foo/*», что приводит к

% mkdir -p /tmp/foo/000f9e956feab3ee4625aebb65ae7bae9533cdbc/bar ... /tmp/foo/ff8b983a7411395344cad64182cb17e7cdefa55e/bar
KJo
источник

Ответы:

13
setopt histsubstpattern extendedglob
mkdir -p /tmp/foo/*(#q/:s_%_/bar_)

Это расширенное глобирование, которое имеет флагq uiet glob, который использует квалификатор glob для сопоставления только каталогов и модификатор для выполнения substitution (использующий %символ шаблона, который доступен только в режиме шаблона подстановки истории ), который добавляет строку к каждому слову.

man zshexpn
JdeBP
источник
Вау, я впечатлен Я даже нашел все это на указанной вами странице руководства.
Wildcard
1
Обратите внимание, что указан оригинальный плакат mkdir -p, который будет немного отличаться от вашей команды не выдавать ошибки, если некоторые из этих каталогов уже имеют barподкаталоги. Незначительный момент, но стоит отметить здесь. :)
Wildcard
1
Другой способ - использовать расширение массива через ${^spec}и добавлять barк каждому элементу все, что /tmp/foo/*(/)расширяется: set -- /tmp/foo/*(/)thenmkdir -p -- "${^@}/bar"
don_crissti
5

Конечно - используйте петлю

for n in /tmp/foo/*; do mkdir "$n/bar";done

Глобусы используются для расширения списков существующих предметов, а не вещей, которые еще не были созданы.

Томас Дики
источник
Извините, боюсь, мой вопрос не был четко сформулирован. Я уточню это.
kjo
2
Это не дает ответа, если zshможно расширить глобусы и добавить текст с одним синтаксисом, но я думаю, что это, вероятно, единственный способ сделать то, что вы хотите, @kjo.
Wildcard
4

Если каталоги находятся в массиве, вы можете использовать ${^...}форму расширения.

a=(/tmp/foo/*/)
mkdir -p ${^a}bar
chepner
источник
0

Вы можете использовать findи xargsсделать это:

find /tmp/foo -maxdepth 1 -mindepth 1 -type d | xargs -i echo mkdir -p {}/bar

который использует -maxdepth 1и -mindepth 1для предотвращения создания barв подкаталогах целей, и /tmp/fooсам по себе соответственно. type dзаставляет рассматривать только каталоги.

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

Руководство говорит , что xargs -iосуждается, но я не нашел никакого другого столь же удобный вариант, так что должно работать в течение нескольких лет ... Вы можете заменить -iс , -I'{}'чтобы всегда быть в курсе , что.

loa_in_
источник
Этот ответ и следующий выглядят хорошо для меня. Может кто-нибудь объяснить, почему они должны быть проголосовали? Отрицательные голоса - это хорошо, но как мы можем узнать, если не указаны причины?
Джо
Это рабочая альтернатива, которая не делает ничего, кроме того, что спросила ОП. Бьет меня
loa_in_
Я думаю, что это какой-то уклон, что ответы должны иметь плохие ответы на них, поэтому предубеждение повлияло на мою репутацию.
loa_in_
Мне не нравятся необъяснимые отрицательные голоса, но я не видел такого смещения. Обычно «плохие» ответы (те, которые я понимаю) на самом деле плохие.
Джо
0

У @loa_in_ было большинство из этого, но findвывод по трубопроводу, как правило, ложная ошибка .

find /tmp/foo -maxdepth 1 -mindepth 1 -type d -exec mkdir {}/bar \;
Sammitch
источник
Я просто использую xargsразные инструменты, у которых нет -execальтернативы, поэтому я использую свой подход, поскольку он одинаково работает со всеми из них.
loa_in_