Bash script to return all elements given an extension, without using print flags

Viewed 59

I want to create shell script that search inside all folders of the actual directory and return all files that satisfy some condition, but without using any print flag. (Here the condition is to end with .py)

What I have done:

find . -name '*.py'| sed -n 's/\.py$//p'

The output:

./123
./test
./abc/dfe/test3
./testing
./test2

What I would like to achieve:

123
test
test3
testing
test2
5 Answers

Use -exec:

find . -name '*.py' -exec sh -c 'for f; do f=${f%.py}; echo "${f##*/}"; done' sh {} +

If GNU basename is an option, you can simplify this to

find . -name '*.py' -exec basename -s .py {} +

POSIX basename is a little more expensive, as you'll have to call it on every file individually:

find . -name '*.py' -exec basename {} .py \;

Using GNU grep instead of sed:

find . -name '*.py' | grep -oP '[^/]+(?=\.py$)'

If portability is not a concern, this is a very readable option:

find . -name '*.py' | xargs basename -a

This is also differentiated from chepner's answer in that it retains the .py file ending in the output.

I'm not familiar with the -exec flag, and I'm sure his one-liners can be customized to do the same, but I couldn't do so off the top of my head.

Chepner's version achieves the same with the small modification:

find . -name '*.py' -exec basename {} \;

if you want the literal output from find and didn't intend to drop the file endings when you used dummy variables (123,test, etc.) in your question.

find shows entries relative to where you ask it to search, you can simply replace the . with a *:

find * -name '*.py'| sed -n 's/\.py$//p'

(Be aware that this skips top level hidden directories)

This might work for you (GNU parallel):

find . -name '*.py*'  2>/dev/null | parallel echo "{/.}"
Related