Im trying to figure out how to write a loop to remove specific files from multiple subdirectories which are all very similar in structure. Within /main_directory/ there are 50 sub directories all with different names. So /main_directory/sub1 /main_directory/testsub1 /main_directory/sub1_practice and so on. Each subdirectory has different file types and I want to remove a specific type, call it .txt.
I want to write a loop something like this: for file in ./main_directory/*; cd $file; rm *.txt; done
So that within each subdirectory in main_directory, all .txt files are removed. Apologies for the basic question, but I can only find solutions for subdirectories that have the same name or prefix, not all differently named subdirectories.
I tried for file in ./main_directory/*; cd $file; rm *.txt; done
and received the error that there is no such file or directory for all the subdirectories
CodePudding user response:
If you cd
into the directory, you have to remember to return to your original working directory afterward otherwise every future command will be executed relative to whatever directory you last successfully changed to.
Some examples that should work:
# don't change directories at all
for dir in ./main_directory/* ; do
rm "$dir"/*.txt
done
# explicitly change back to the original directory
for dir in ./main_directory/* ; do
cd "$dir" && { rm *.txt ; cd - ; }
done
# change directories in a subshell, so that your
# original working directory is restored afterward
for dir in ./main_directory/* ; do
(
cd "$dir" && rm *.txt
)
done
# without a loop, using the find command
find ./main_directory -type f -name '*.txt' -delete
CodePudding user response:
After descending in the first directory, you don't return to the original location. The second directory will be searched for in the first one. An improvement of your code will be adding cd ..
for directory in ./main_directory/*; do
cd "$directory" || continue
rm *.txt
cd ..
done
This code is wrong without the || continue
part.
When the cd "$directory"
fails, it will start removing files from the wrong location and next put you in the parent directory. You can change it into cd "$directory" || continue
.
An alternative is starting it in a subprocess: for directory in ./main_directory/*; do ( cd "$directory" || continue rm *.txt ) done
You still need the || continue
, because you don't want to remove files from the wrong directory.
In this example, you don't need a loop. You can use
rm main_directory/*.txt