how to navigate to subdirectories in a shell script
I am having a directory.This directory has a lot of subdirectories which contain html pages and some c source code fi开发者_开发知识库les,Makefiles etc etc.The script I am trying to write would be executed from one directory which has all these subdirectories. Following is the set of directories and files you can see
ls
delete.sh lddbus Makefile misc-progs sbull scullc scullp short simple snull usb
include LICENSE misc-modules pci scull sculld scullv shortprint skull tty
Some of them are directories and some are files in the subdirectories above there are further subdirectories and html pages also which I want to eliminate. The manual way would be do go to each directory and remove the pages via following command
rm *.html*
Since the html page has name ending with ?=/something
sort of names.
So I decided to write a shell script.
But what I am not clear is how will I take directory names as arguments in my shell script.If I decided to use a for loop or some thing similar.
In this case what should I be doing?
I do not want to use
find . -name '*.html*' -exec rm -f {} \;
As I am doing this for learning purpose.
With bash 4 (or zsh) you can use globstar "**" to match recursively.
shopt -s globstar
echo **/*html*
With a directory setup like this:
mkdir -p {a..b}/{c..d}
touch {a..b}/{c..d}/{e..f}.{htmlx,other}
It will result in:
a/c/e.htmlx a/c/f.htmlx a/d/e.htmlx a/d/f.htmlx b/c/e.htmlx b/c/f.htmlx b/d/e.htmlx b/d/f.htmlx
This code snippet will run ls
for every subdirectory in current dir:
for d in * .[!.]* ..?*; do
test -d "${d}" && ls "${d}"
done
You can adapt it to run a command, for each subdirectory, that you like.
If you want to get deeper in the directory hierarchy, you can wrap this code in a function and rerun it for every subdir.
function f {
cd "$1"
# do something in this dir
for d in * .[!.]* ..?*; do
cd "$1"
test -d "$1/$d" && f "$1/$d"
done
}
f "`pwd`"
For Zsh you'd probably want to set NULL_GLOB option (-G switch), so it doesn't report errors if there are no hidden dirs, in Bash it works by default.
find
is the way to go. You will not learn anything useful choosing the wrong way to solve a problem.
Print a list of files you want to remove
find /your/dir -type f -iname '*.html*'
and delete them
find /your/dir -type f -iname '*.html*' -delete
find
is a powerful command, learn to use it.
Another way to improve the command you don't want to use:
find /your/dir -type f -name '*.html*' -exec rm -f {} +
(hint: man find
to learn how -exec ;
and -exec +
differ)
Note that shell scripting is just using in the best useful way the small programs like find
, cat
, ls
, wc
, etc. Knowing these utilities thoroughly is a necessary requisite to learn shell scripting.
Create a function like so:
myfunc()
{
for dir; do
if [[ -d "$dir" ]]; then
echo rm -rf "${dir}/*.html*"
else
echo "No such dir '$dir'"
fi
done
}
Then call the function by passing the directories you want to remove .html from
Output
$ myfunc /foo /etc /root
No such dir '/foo'
rm -rf /etc/*.html*
rm -rf /root/*.html*
Once you are satisfied with the output, remove the echo
to have it really delete the files.
This is based on maarons' answer, but with two advantages:
- Using
*/
instead of*
in thefor
loop means it only iterates over directories instead of all files for a potentially big speedup - Using
pushd
andpopd
makes it easy to support.
or no argument to mean the current directory.
Here is the function:
g () {
local d bb=/dev/null # bit-bucket
pushd "$1" > $bb
pwd # do something (pwd is a placeholder)
for d in */
do
test -d "$PWD/$d" && g "$PWD/$d" # you could use $(pwd) instead of $PWD
done
popd > $bb
}
Of course, using find
with -execdir
is simpler and gives the same results.:
find -mindepth 1 -type d -execdir sh -c 'cd {}; pwd' \; # (pwd` is a placeholder)
精彩评论