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). Commented Jul 28, 2016 at 22:26
  • What should the resulting directory structure look like? Please edit the question with these results. Commented Jul 28, 2016 at 22:28
  • "The instruction is" -- is this homework? :) Or is there some other reason to specifically not use sed? Commented 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. Commented 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. Commented 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. Commented 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. Commented 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) Commented Jul 29, 2016 at 1:19

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.