Issue
I am new to bash (but not to programming). I have a bash script that looks for all .txt
files in a project
for i in `find . -name "*.txt"`;
do
basename= "${i}"
cp ${basename} ./dest
done
However, I would like to get the .txt files only from a specific sub directory. For e.g this is my project structure:
project/
├── controllers/
│ ├── a/
│ │ ├── src/
│ │ │ ├── xxx
│ │ │ └── xxx
│ │ └── files/
│ │ ├── abc.txt
│ │ └── xxxx
│ └── b/
│ ├── src/
│ │ ├── xxx
│ │ └── xxx
│ └── files/
│ ├── abcd.txt
│ └── xxxx
├── lib
└── tests
I would like to get .txt
files only from controllers/a/files
and controllers/b/files
. I tried replacing find . -name "*.txt"
with find ./controllers/*/files/*txt
, it works fine, but errors out on GitHub actions with No such file or directory found
. So I'm looking for a more robust way of finding .txt
files from the subdirectory without having to hardcode the path in the for loop. Is that possible?
Solution
You can use brace expansion for the search directory, e.g.
find ./project/controllers/{a,b} -type f -name "*.txt"
To select file only below ./project/controllers/a
and ./project/controllers/b
Additionally, your use of basename
would no longer be needed in your script (and cure the error with the ' '
(space) to the right of the '='
sign. Traditionally in bash, you will use process substitution to feed a while
loop rather than using a for
loop, e.g.
while read -r fname; do
# basename="${fname}" # note! no ' ' on either side of =
cp -ua "$fname" ./dest
done < <(find ./project/controllers/{a,b} -type f -name "*.txt")
Edit Based On Comment of Many Paths
If you have many controllers
not just a
and b
, then using the -path
option instead of the -name
options can provide a solution, e.g.
find . -path "./project/controllers/*/files/*.txt" -type f
would select any ".txt"
files below any directory below controllers
that contains a files
directory.
Answered By - David C. Rankin Answer Checked By - Mary Flores (WPSolving Volunteer)