开发者

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 the for loop means it only iterates over directories instead of all files for a potentially big speedup
  • Using pushd and popd 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)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜