find . -iname "*.sh" -exec basename {} \; | sed s/\.sh//g
basename
Утилита удаляет все данные каталога с пути - абсолютного или относительного.
dirname
Утилита делает обратное, если это необходимо.
find . -iname "*.sh" | sed 's/[.]sh$//' ./backup/samukano/ex04/who_am_i ./backup/samukano/ex05/people ./days/day01/samukano/ex01/print_groups ./days/day01/samukano/ex02/find_sh ./samukano/ex04/who_am_i ./samukano/ex05/people
А мне нужно просто
who_am_i people ... people
find . -iname "*.sh" -exec basename {} \; | sed s/\.sh//g
basename
Утилита удаляет все данные каталога с пути - абсолютного или относительного.
dirname
Утилита делает обратное, если это необходимо.
Портативный, не прочный:
find . -type f \( -name "*.sh" -o -name "*.Sh" -o -name "*.sH" -o -name "*.SH" \) | sed -e 's|^.*/||' -e 's/[.][sS][hH]$//'
Надежный, для анализа в виде строк с нулевым символом в конце:
find . -type f -iname "*.sh" -printf "%f\0" | sed -z 's/[.][sS][hH]$//'
Внутренне устойчивый с возможно неоднозначным выводом, для просмотра:
find . -type f -iname "*.sh" -printf "%f\0" | sed -z 's/[.][sS][hH]$/\n/'
Есть много способов, некоторые более надежные, чем другие. Кроме того, инструменты, которые вы, возможно, захотите использовать, имеют перекрывающиеся возможности, хотя многие из них не POSIX, поэтому вы можете иметь или не иметь требуемые опции.
Кроме того, любой каталог с именем файла может содержать символы новой строки и другие странные символы. По этой причине, чтобы анализировать имена файлов надежным способом, вы хотели бы рассматривать их как строки с нулевым символом в конце.
Тогда вы можете распечатать результат в виде строк с новой строкой (то есть регулярных) в любом случае для удобства чтения (хотя и рискуете получить неоднозначный вывод).
Инструменты обычно поддерживают строки с нулевым символом в конце с расширениями, отличными от POSIX.
Например, чтобы избавиться от этих полных путей, которые являются основной проблемой, вы можете использовать:
find . -printf "%f"
, но вы find
можете или не можете поддержать -printf
;basename
;sed
.Для раздевания .sh
вы можете использовать:
basename path_to_process .sh
, но он чувствителен к регистру, и я думаю, что вы использовали -iname
по причине (примечание -iname
не требуется POSIX);sed
(как вы сделали), что можно сделать без учета регистра.Этот анализ не является исчерпывающим.
Самая надежная версия без учета регистра возвращает строки с нулевым символом в конце. Это делает вывод полностью надежным для дальнейшего анализа:
find . -type f -iname "*.sh" -printf "%f\0" | sed -z 's/[.][sS][hH]$//'
То же самое, возвращая читабельный и, возможно, неоднозначный вывод:
find . -type f -iname "*.sh" -printf "%f\0" | sed -z 's/[.][sS][hH]$/\n/'
Неоднозначность проявляется так:
foo bar
Были ли два сценария: foo.sh
а bar.sh
? или только один foo(newline here)bar.sh
?
Это станет еще более запутанным, если вы не сможете использовать sed -z
и должны предоставлять ввод в sed
виде строк с новой строкой. В этом случае один файл foo.sh(newline here)bar.sh
также будет генерировать вышеуказанный вывод.
Что делать, если ваши sed
поддерживает, -z
но find
не поддерживает -printf
? Может быть, ваши basename
поддерживает -z
. Это должно быть полностью надежно:
find . -type f -iname "*.sh" -exec basename -z -a {} + | sed -z 's/[.][sS][hH]$//'
или без поддержки -a
:
find . -type f -iname "*.sh" -exec basename -z {} \; | sed -z 's/[.][sS][hH]$//'
Я вижу, что ваша find
поддержка поддерживает -iname
, хотя, возможно, нет. Что если это не так? Довольно наивный, но рабочий подход:
find . -type f \( -name "*.sh" -o -name "*.Sh" -o -name "*.sH" -o -name "*.SH" \) ...
Как видите, все зависит от доступных опций.
Наконец, давайте предположим, что ваши пути используют безопасный набор печатных символов (без перевода строки и т. Д.). Эта команда должна быть переносимой и достаточно хорошей:
find . -type f \( -name "*.sh" -o -name "*.Sh" -o -name "*.sH" -o -name "*.SH" \) | sed -e 's|^.*/||' -e 's/[.][sS][hH]$//'