Sumsarium
Sumsarium

Reputation: 1

Moving folders if they or their subfolders contain specific files (bash)

I am new to bash scripting and stackoverflow (first question). I am trying to do a fairly simple thing but I am somehow not getting what I want (tried to use some of the solutions from different threads but with no luck). Perhaps you can help me with a simple solution.

My task: Look through different folders (in some main folder) for for a file named log.txt. If found then move the relevant folder to another location (its a backup folder...the log.txt indicates that this folder needs a backup). In the below layout, I want to mv folder3 along with all its content.

-Main
--folder1   
  ---subfolder
--folder2
  ---Subfolder2
--folder3   
   --Subfolder3
        --log.txt

#!/bin/bash
MAIN=$(find /home/rwo/Desktop/FROM/* -maxdepth 0 -type d)
for FOLDER in $MAIN; do
        if 
            find $FOLDER -maxdepth 0 -type f -name "log.txt" 
                then
                    mv $FOLDER /home/rwo/Desktop/TO

        fi
done

In the above case, the recipient folder (TO) ends up receiving Subfolder1, Subfolder2 and Subfolder3 (along with log.txt). What am I doing wrong?

Thanks in advance

Upvotes: 0

Views: 172

Answers (1)

Jetchisel
Jetchisel

Reputation: 7791

With find and bash

#!/usr/bin/env bash

while IFS= read -r file; do
  file=${file%/*}
  echo mv -v "${file%/*}" /home/rwo/Desktop/TO
done < <(find main -type f -name 'log.txt')

The echo is there to show you what's going to happen, remove it if you think the output is ok.


A simple simulation

mkdir -p Main/folder{1..3}
mkdir -p Main/folder1/subfolder
mkdir -p Main/folder2/subfolder2
mkdir -p Main/folder3/subfolder3
touch Main/folder3/subfolder3/log.txt

Create the destination directory

mkdir -p home/rwo/Desktop/TO

check the what is inside the Main directory.

tree Main

Output

Main
├── folder1
│   └── subfolder
├── folder2
│   └── subfolder2
└── folder3
    └── subfolder3
        └── log.txt

6 directories, 1 file

Now the script to match the Main

#!/usr/bin/env bash

while IFS= read -r file; do
  file=${file%/*}
  echo mv -v "${file%/*}" home/rwo/Desktop/TO
done < <(find Main -type f -name 'log.txt')

output

mv -v Main/folder3/ home/rwo/Desktop/TO

Removing the echo will output

renamed 'Main/folder3/' -> 'home/rwo/Desktop/TO/folder3'

The "${file%/*}" is form of Parameter Expansion Which basically removes the last /

So for example the output of find main -type f -name 'log.txt'

main/folder3/subfolder3/log.txt

Removing the last / with parameter expansion will leave just the path name

main/folder3/subfolder3/

Apply another parameter expansion to remove the last / will result to

main/folder3/

Then feeding that to mv as an argument inside the while read loop.

The <() is called Process Substituion

The IFS= disables the default feature of the builtin read which removes the trailing and leading white spaces.

Have a look at howto read a file or stream in bash to understand the while read loop that is posted.

Upvotes: 1

Related Questions