Учитывая структуру папок
/recipes/foo/.env
/recipes/bar/.env
Выполнение следующей команды:
find ./recipes -type f -name '.env' -print0 | xargs -0 dirname | xargs -0 basename
Output:
foo
Обрезка команды до:
find ./recipes -type f -name '.env' -print0 | xargs -0 dirname
Output:
./recipes/bar
./recipes/foo
Поэтому по какой-то причине передача имени каталога в базовое имя приводит к потере некоторых найденных каталогов.
Здесь есть 2 проблемы:
Опция -0
для xargs
указывает, что входы разделены NUL, а не выходы. Чтобы передать вывод xargs -0 dirname
в xargs -0 something
, вы должны использовать опцию -z
для dirname
, если она поддерживается (это не POSIX). В противном случае его вывод разделяется символом новой строки.
basename
по умолчанию не поддерживает несколько аргументов. Если ваш поддерживает это (это не POSIX), вы можете попробовать -a
или --multiple
.
find ./recipes -type f -name '.env' -print0 |
xargs -0 dirname -z | xargs -0 basename -a
В противном случае используйте опцию -n1
для xargs
:
find ./recipes -type f -name '.env' -print0 |
xargs -0 dirname -z | xargs -0 -n1 basename
Примечание: поскольку ваш find
, очевидно, GNU find
, вы можете пропустить dirname
с помощью:
find ./recipes -type f -name '.env' -printf '%h\0' | xargs -0 basename -a
Примечание: вы также можете использовать только find
и любую оболочку POSIX:
find ./recipes -type f -name '.env' -exec sh -c '
d = "${1%/*}"; printf "%s\n" "${d##*/}"' _ {} \;
Примечание. Если, как в примере, который вы показываете, глубина файлов .env
равна 2, вам не нужны find
, xargs
, dirname
или basename
. Вашей (POSIX) оболочки достаточно (плюс утилита printf
, если она еще не встроена в вашу оболочку):
for f in recipes/*; do [ -f "$f/.env" ] && printf '%s\n' "${f##*/}"; done
@dave_thompson_085. Да, но поскольку RS='\0'
не является POSIX, для этого требуется GNU awk
или другой awk
, поддерживающий его.
-print0
также не является POSIX, и если вы опустите это (и не будете использовать новую строку в своих именах путей, что делает только сумасшедший), POSIX awk \n будет работать
@dave_thompson_085 Я полностью согласен с тобой, Дэйв, и поскольку find
ОП, очевидно, является GNU find
, мы можем предположить, что их awk
тоже GNU. Мы также можем предположить, что в их путях нет символов новой строки. Моя личная позиция (можете не соглашаться) заключается в том, что не зная, кто будет читать эти вопросы и ответы и что с ними будут делать, я предпочитаю пытаться предложить решения, которые не смогут сломаться, даже с малой вероятностью. И я не говорю, что мне всегда это удается. Просто пытаюсь. Итак, если бы я добавил ваше решение на основе awk
к своему (и без того слишком длинному) ответу, я бы также добавил только GNU.
или
find ... -print0 | awk -vRS='\0' -F/ '{print $(NF-1)}'