I am making a script to simplify my daily tasks. Everyday, I have to grep for a few things inside a company server. It was okay, however, now, they have segregated each object into sub directories. I am looking for a solution in which my existing shell script will execute repeatedly into each sub directory inside a certain directory. How do I do this? I am quite new to Ubuntu and still learning the ropes.

Here's my script:


#fetch start time of uut
grep -i "01_node_setup" his_file | tail -1 >> /home/xtee/sst-logs.out

#check if sysconfig.out exists
if [ -f sysconfig.out];
    grep -A 1 "Drive Model" sysconfig.out | tail -1 >> /home/xtee/sst-logs.out
    grep -m 1 "Pair0 DIMM0" node0/trans_file_prev/*setupsys* | tail -1 >> /home/xtee/sst-logs.out

Basically I want to run this script to execute on all the existing sub directories of a certain directory. What do I do? Thanks!

  • Do the subdirectories have spaces in their names? Something simple you could do is for dir in $(ls); do ...; done, but it'll only work if names don't have spaces. – Mark Paskal Aug 2 '12 at 10:07
  • Hi @MarkPaskal, no the subdirectories do not have spaces. Thanks! Will try this. :) Can this be done if let's say I just want to traverse just one sub directory deep? – JudeJitsu Aug 2 '12 at 10:11
  • @JudeJitsu edited my answer, should work for all dirs even with spaces. – Bruno Pereira Aug 2 '12 at 11:33
  • IIRC grep has a recursive flag? you could have grepped * with that flag and it would work? – jackweirdy Aug 2 '12 at 16:13
  • 1
    @Mark: You should never parse the output of ls. It's impossible to do so in a way that's guaranteed to work in all cases, and the proper way is simpler anyway. Try this: for file in *; do ...; done – Scott Severance Aug 2 '12 at 23:32

This should more or less do the trick. I am assuming that the 'node0' dir will be within the subdirectories if 'sysconfig.out' is not and that 'his_file' is also in the subdirectories.

# cd into dir
cd $MainDir

for dir in *; do

#fetch start time of uut
grep -i "01_node_setup" $dir/his_file | tail -1 >> /home/xtee/sst-logs.out

#check if sysconfig.out exists
if [ -f $dir/sysconfig.out];
    grep -A 1 "Drive Model" $dir/sysconfig.out | tail -1 >> /home/xtee/sst-logs.out
    grep -m 1 "Pair0 DIMM0" $dir/node0/trans_file_prev/*setupsys* | tail -1 >> /home/xtee/sst-logs.out


#cd back to where we started
  • Okay, this worked but when I run the script, it displays [: 19: missing ] and the sst-logs.out file displays binary file /sub/directory/ as opposed to adding the output of the grep. – JudeJitsu Aug 2 '12 at 10:53
  • 1
    Never use ls to iterate files. Please see mywiki.wooledge.org/BashPitfalls – geirha Aug 2 '12 at 16:07
  • 1
    Also, you should surround variable expansions with double quotes, in case their values contain spaces or other "special" characters. E.g., "$foo", not $foo. – Scott Severance Aug 2 '12 at 23:46
  • Using ls with a for loop to iterate files doesn't work if you quote the list of items to loop through. I understand that this method sucks (mainly because filenames with spaces wont work at all) but in this case it was known that the output of ls would not contain folder names with spaces. Thanks for your link @geirha – Mark Paskal Aug 3 '12 at 2:51

You can iterate subdirs with a for-loop like this

#!/usr/bin/env bash

for dir in /the/path/*/; do
    awk 'tolower($0) ~ /01_node_setup/{line=$0} END{print line}' "$dir/his_file"

    if [[ -f "$dir/sysconfig.out" ]]; then
        awk '/Drive Model/{getline line} END{print line}' "$dir/sysconfig.out"
        awk '/Pair0 DIMM0/{print;exit}' "$dir/node0/trans_file_prev"/*setupsys*
done >> /home/xtee/sst-logs.out

I changed your greps into awks that should be more portable. I believe they should produce the same output. The important parts are the quotes around the paths.

  • Great! Thanks for sharing some scrip fu skills! ;) (I cleaned all the comments here, hope that is ok) – Bruno Pereira Aug 3 '12 at 13:38

An easier, though less elegant, way to iterate subdirectories is this:


iterator() {
  local dir="$1"
  local i=
  for i in "$dir"/*; do
    if [[ -d "$i" ]]; then
      iterator "$dir/$i"
      # do something with this file

iterator "$base"
  • You're missing a glob there – geirha Aug 3 '12 at 6:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.