0

I am trying to rename a few directories that contain "Fever" to contain "Malaria" instead. The instruction is to do it without sed or rename. So far, my errors include mostly lines like mv: cannot stat ‘retest\nretest/Section-01\nretest/Section-02\nretest/Section-03\nretest/Section-04’: No such file or directory.

The best my code have done is rename directories in the first level.

Here's my directory structure:

Fever-A/Malaria-A-A

Fever-B/Fever-B-A

Fever-B/Fever-B-B

Fever-C/Malaria-A

Fever-C/Fever-C-A

Fever-C/Fever-C-B

Fever-C/Fever-C-C-C

Fever-D/Malaria-A

Fever-D/Malaria-B

The code I have so far is :

#!/bin/bash

# Access directory
#cd $1

# Find all subdirectories in $1 and load up array
all=($(find $1 -type d))
#echo ${all[@]}

# Loop through directories above
for dir in ${all[@]}
do
    # echo "$dir"
    cd $dir
    # List files with "Section" in name
    subdir=(:"Section*")

    # A second loop for directories in each dir with "Section*"
    for item in ${subdir[@]}
    do
            echo $item
            echo "--------------------"

            # Rename operation
            mv $item ${item//Fever/Malaria}
    done
    cd $1
done

Another approach I've considered is using a function like so, but it's not working either:

#!/bin/bash

rename(){
    old_names=($(find $1 -maxdepth 1 -type d))

    for item in ${old_names[@]}
    do
            if [[ $item = *Section* ]]; then
                    new_name=${item//Fever/Malaria}
                    mv $item $new_name
            elif [[ $1 != $item ]]; then
                    rename $item
            fi

            rename $1
    done
}

rename $1
5
  • 1
    There are several questions on this subject if you search rename tag... There are answers that show how to do this properly (that is, using find with -exec and -depth) and some of them use just parameter expansion (no sed, no perl rename). Jul 28, 2016 at 22:26
  • What should the resulting directory structure look like? Please edit the question with these results. Jul 28, 2016 at 22:28
  • "The instruction is" -- is this homework? :) Or is there some other reason to specifically not use sed?
    – ilkkachu
    Jul 29, 2016 at 6:48
  • @ilkkachu Tools like sed and rename make things easy true, but I'm wondering what really happens under the hood. The resulting directory structure remains the same.
    – IshMary
    Jul 30, 2016 at 7:04
  • Under the hood, a bunch of getdents(2) (or readdir(3)) calls are made to list the files during a recursive walk of the tree, and the files are then moved with calls to rename(2)... You could implement the recursive logic with shell functions, but to get a bit closer to the OS interface, you'd better write a C program.
    – ilkkachu
    Jul 30, 2016 at 7:57

2 Answers 2

1

As Don Crissti mentions, there are a lot of ways of solving this with find. But I thought, since we're only talking two directory levels, that we can do this slightly differently with only one external command: mv

#!/bin/bash

fixdir()
{
  local f g

  for f in Fever*
  do
    if [ -e "$f" ]
    then
      g=Malaria"${f#Fever}"
      if [ -e "$g" ]
      then
        echo "Skipping $1/$f->$1/$g; already exists"
      else
        # echo "Renaming $1/$f->$1/$g"
        mv "$f" "$g"
      fi
    fi
  done
}

for a in *
do
  if [ -d "$a" ]
  then
    (cd $a ; fixdir $a )
  fi
done

fixdir .

The results:

$ ls -1d F*/*
Fever-A/Malaria-A-A
Fever-B/Fever-B-A
Fever-B/Fever-B-B
Fever-C/Fever-C-A
Fever-C/Fever-C-B
Fever-C/Fever-C-C-C
Fever-C/Malaria-A
Fever-D/Malaria-A
Fever-D/Malaria-B

$ ./fix

$ ls -1d M*/*
Malaria-A/Malaria-A-A
Malaria-B/Malaria-B-A
Malaria-B/Malaria-B-B
Malaria-C/Malaria-A
Malaria-C/Malaria-C-A
Malaria-C/Malaria-C-B
Malaria-C/Malaria-C-C-C
Malaria-D/Malaria-A
Malaria-D/Malaria-B
0

What about:

for dir in $(find /startdir -depth -type d -name '*Fever*')
do   dn=$(basename $dir)
     mv $dir $(dirname $dir)/${dn//Fever/Malaria}
done

That should do it. (Change startdir to your start directory)

The find will only return directories containing 'Fever'. the mv command uses bash inline substitution to return a string with Fever changed to Malaria.

The added -depth makes it process subdirs first.

3
  • What happens to /startdir/Fever-A/Fever-A ? That'll result in mv /startdir/Fever-A/Fever-A /startdir/Malaria-A/Malaria-A but that directory doesn't exist... or if 'Fever-A' gets renamed first then the find will then start looking for a directory that doesn't exist and won't find the new Malaria-A/Fever-A. Jul 28, 2016 at 22:41
  • Good catch! Added a -depth to process subdirs first, and some more cruft to rename only the end directory segment.
    – P. Heffner
    Jul 29, 2016 at 1:01
  • 1
    Good update. Now the next problem; what if there's a directory called Fever A-B - ie has a space in it? (I'm not picking on you; this is a good learning opportunity - there's a lot of hidden gotchas in something so simple! Let me know if you don't want to do this here and I'll stop) Jul 29, 2016 at 1:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .