ТЛ; др
Портативный, не прочный:
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]$//'