Home > Software engineering >  How to recursively read a folder and its sub-folders and search for a file
How to recursively read a folder and its sub-folders and search for a file

Time:12-11

I'm new to shell scripting, so I'll do my best to summarize everything.

I am writing a script with the goal of going into a directory, searching for a file (readme.txt) within each subfolder and follow instructions specified in file (readme.txt).

Code I have written so far:

#! /bin/bash

# Creating directory that the files are going to be moved into

if ! (mkdir /dir1/dir2/backupdir> /dev/null); then
    echo "Directory already exists. "

else
    echo "Directory successfully created. "

fi

# Moving old files to backup directory

cd /dir1/dir2/maindir-*
find /dir1 -mindepth 1 -type f -name "readme.txt" | while read z

do
    if grep -i move "$z" > /dev/null; then

        mv /xdir0/$z /dir1/dir2/backupdir
        # /xdir0/ is the parent directory of /xdir1/
        # readme.txt file does not include /xdir0/ so I added it when moving the files
        
    fi
               
done

Current Output: /dir1/dir2/maindir/subfolder1/readme.txt

Within 'maindir' there are several sub-folders.

maindir/subfolder1 maindir/subfolder2 maindir/subfolder3

Each subfolder has a readme.txt file. The contents of readme.txt would look something like this:

Date: 2021-08-12
Applicable Version: xx.x
Description: Quick summary of files

Steps to apply:
 1. move the following files into a backup location
    * xdir1/xdir2/xdir3/xdir4/filename-*.jar
    * xdir1/xdir2/xdir3/xdir4/filename1-*.jar
 2. done. work completed.

The script would parse through each line after "move" is recognized and stop at the "Done. Work completed" line as all files have been moved to the backup directory I created.

Any help would be greatly appreciated.

CodePudding user response:

You can use mkdir -p newfolder which will create it or silently continue if the folder already exists. This way you would not have to check if the folder exists.

You do not need the sleep 1

You can actually first use find -mindepth 1 -type f -name "readme.txt" to find the folders where you have the readme:

find /dir1 -mindepth 1 -type f -name "readme.txt"|while read z
do
  if grep -i move "$z" > /dev/null;then
    ... do your mv magic
  fi
done

CodePudding user response:

The best way is to use a pipe, you start calling find:

# find all 'readme.txt' files from "$DIR" and subdirectories and make a loop
# for each one.
your_backup_location=/home/user/blah/blah/foo/bar

find "$DIR" -name 'readme.txt' -print | while read file
do
    # Assuming this is executed in subdirectory
    # xdir1/xdir2/xdir3/xdir4, where readme.txt was found...
    # $file contains the readme.txt full path from starting dir.
    echo "executing commands from $file" >&2 # print it on stderr
    ( # this will start a subshell, so we can work in the directory where readme.txt is.
        cd "$(dirname "$file")"  # move to dir where readme.txt is located.
        . readme.txt # read commands from readme.txt file.  Protect comment lines with # char.
        # as commands are read into the shell, no need to export the 
        # shell variable ${your_backup_location} (see below)
    ) # exit subshell, so we are back in start directory.
done

and the readme.txt format should be a shell commented text file (explaining in comments what needs to be done) interspersed with shell commands to execute:

# Date: 2021-08-12
# Applicable Version: xx.x
# Description: Quick summary of files

# Steps to apply:
#  1. move the following files into a backup location
#     * xdir1/xdir2/xdir3/xdir4/filename-*.jar
        mv filename-*.jar ${your_backup_location}
#     * xdir1/xdir2/xdir3/xdir4/filename1-*.jar
        mv filename-*.jar ${your_backup_location}
#  2. done. work completed.

This way you will start a subshell on every directory in which you have a readme.txt file. You can specify many filters on find command, so try to output only what is needed to do some actual work, and don't try to spawn a subshell for each subdirectory just to do nothing. And don't use find to just descend one level each time, as you will have a lot of find processes running to do almost nothing.

The idea is not to do unnecessary processing if you have no strict formatting rules to describe the actions to be done. In this case, shell comments allow you to fully describe the operations, while you can better describe the operations with valid shell commands. This saves a lot of grep and sed employed in other answers.

  • Related