Мне нужно найти файл * .sh из моего каталога и подкаталогов и отобразить их без полного пути

391
Saken
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 
0

2 ответа на вопрос

1
ivanivan
find . -iname "*.sh" -exec basename {} \; | sed s/\.sh//g 

basenameУтилита удаляет все данные каталога с пути - абсолютного или относительного.

dirnameУтилита делает обратное, если это необходимо.

Ваша команда "sed" хуже, чем команда OP. Посмотрите, что он делает с `what.a.shame.sh`. Kamil Maciorowski 5 лет назад 0
0
Kamil Maciorowski

ТЛ; др

Портативный, не прочный:

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]$//'