3

Within my parent_directory, I have subdirectories labeled E-11_G, and E-10_G. Within each of those subdirectories, I have more subdirectories labeled E-2_U, E-1_U, and E0_U. In each of those folders, I'm performing commands on these files: ander, ander.band, ander.data, ander.in, and ander.log.

Here's a better picture:

                               parent_directory
                                      ↓
                               E-11_G/ E-10_G/ 
                                  ↓
                          E-2_U/ E-1_U/ E0_U/ 
                            ↓
            ander  ander.band  ander.data  ander.in  ander.log

I want to write a more efficient version of this:

#!/bin/bash

cd parent_directory/E-11_G/E-2_U/; 
ls -l ander ander.band ander.data;
cat ander.in;
cat ander.log;
pwd;
cd ../E-1_U;
ls -l ander ander.band ander.data;
cat ander.in;
cat ander.log;
pwd;
cd ../E0_U;
ls -l ander ander.band ander.data;
cat ander.in;
cat ander.log;
pwd;
cd ../../E-10_G/E-2_U/;
ls -l ander ander.band ander.data;
cat ander.in;
cat ander.log;
pwd;
cd ../E-1_U;
ls -l ander ander.band ander.data;
cat ander.in;
cat ander.log;
pwd;
cd ../E0_U;
ls -l ander ander.band ander.data;
cat ander.in;
cat ander.log;
pwd;

I've already been able to successfully run this script as is, however, I really need a much more simpler and efficient way of writing it because I'm actually working with a lot more directories than I presented. My reason for doing this is because I need to keep certain records of each of those 'ander' files for each subdirectory. I'm basically planning on running this script and exporting everything that shows up onto the terminal window into a text file using shell > export text as. This is why I want the records for each directory in numerical order.

How can I make my script more efficient? This is the kind of thing I'm aiming for:

#!/bin/bash

cd parent_directory/;

do i= -11, -10 
   do j= -2, 0
      cd  E-i_G/E-j_U/;
      ls -l ander ander.band ander.data;
      cat ander.in;
      cat ander.log;
      pwd;
   end
end

I know that’s pretty much written in Fortran, but is there anything equivalent or similar to this in bash scripting? I've been trying to use 'for loops', but I just can't seem to write them in a way that would give me the same results as my first script.

4
cd parent_directory/

for i in {-11..-10}
do
   for j in -2 0
   do
      (
      cd  "E${i}_G/E${j}_U/"
      ls -l ander ander.band ander.data
      cat ander.in
      cat ander.log
      pwd
      )
   done
done

Notes:

  • You can loop over a range of numbers by using the braces notation:

    for i in {-11..-10}
    
  • You can also loop over an explicit list of items:

    for j in -2 0
    
  • You can change the directory so some place that depends on variables:

    cd  "E${i}_G/E${j}_U/"
    
  • The argument to the cd command is a directory specified relative to the current directory. After we have done our work in that directory, we want to change back to the parent_directory. There are many ways to deal with this but one simple way is to do that is to put the cd command and commands to be performed in that directory into a subshell, denoted by parens. After we exit the parens, the directory is automatically restored to what it was before.

  • 1
    It worked!! I just had to change cd "E-${i}_G/E-${j}_U/" to cd "E${i}_G/E${j}_U/" Thank you so much!! – SpaceKidd_N7 Nov 11 '14 at 4:41
  • @AaronMohammed Thanks for catching that! Answer updated. – John1024 Nov 11 '14 at 4:46
0

As a more general solution, you can use xargs. This way you can decouple the action from the list of directories you want to operate on.

First write a script that performs the actions you need:

perform_ander.sh

#!/bin/bash

# Exit immediately on error
set -e

if [[ $# -ne 1 ]] ; then
  echo "USAGE: $0 DIRECTORY" >&2
  exit 1
fi

cd "$1"

ls -l ander ander.band ander.data
cat ander.in
cat ander.log
pwd

Mark the script as executable:

chmod +x perform_ander.sh

Finally run:

find -type d -name 'E*_U' | xargs -n1 ./perform_ander.sh

Explanation

find

The find command outputs all matching files to stdout

-type d limits the search to directories

-name 'E*_U' limits the search to directories that match the glob

xargs

The xargs command uses its standard input as a source of arguments, and calls the given commands with those arguments.

-n1 specifies that no more than 1 argument is passed at a time.

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.