Need to search "Directory" for common character/string and replace with supplied string

Posted on 2004-08-15
Last Modified: 2010-04-21
I am new to this system... as well as Linux, so forgive the expected nievity of the question.  

I need to search a list of directory names (no sub directory search needed) for a common string.  Once detected, I would like to replace the found string with a given string.

 Example (directory names): n113, n21, N342
change to:  Nordic113, Nordic21,Nordic342

Please note the lack of case sensitivity.  If I have to run two commands (one for upper case, and another for lower) then that is not a problem.  Also, I am not seeking to change any of the included filenames that reside within the directories.

Any help would be appreciated.
Question by:Jawanza
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
  • 3
  • +2
LVL 23

Expert Comment

ID: 11805096
cd /path/to/parent/directory
for f in `find . -name "[nN][0-9]*" -a -type d -a -maxdepth 1` ; do mv $f ${f/^[nN]/Nordic} ; done


Author Comment

ID: 11805200
Did not seem to work... keeps giving me the following error message.

[vhs@s2 vhs]$ for f in 'find . -name "[nN][0-9]*" -a -type d -a -maxdepth 1'; do mv $f${f/^[nN]/Novice};done
mv: invalid option -- n
Try `mv --help' for more information.
LVL 23

Expert Comment

ID: 11805694
The single quotes (') around the find command should be back quotes (`).
There also seems to be a space missing in the mv command.  I think there is some
copy-paste character translation foo going on here...  unless you mis-typed it rather
than copy-paste.

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

LVL 22

Expert Comment

ID: 11806081
Seems like a job for awk - not necessarily the most succinct way to do it, but probably the easiest to understand and reuse:

find path -type d | awk '/[nN][0-9]+$/{original=$1; sub (/\/[nN][0-9]+$/,""); root= $1; $1=original; sub (/.*\//,"/Nordic"); print "mv " original " " root $1;}' | /bin/bash

Best I explain what is going on here! This is broken down into nice easy steps so don't panic!


find path -type d

This finds all directories within the given path.

This output is piped into awk for it to act upon. First the matching - /[nN][0-9]+$/
This means that the directory name must match the letter n or N followed by the number 0-9 any number of times (the +), and the $ indicates that this match must be at the end of the directory.

Now the script:
First make a copy of the directory name

Substitute all of the end of the directory name (the nN[0-9]+$) bit with nothing - i.e, strip this off, and then call this bit root (root=$1).

Then restore $1 from teh original and strip off everything up to the n or N and replace it with Nordic.

Finally print all the bits together. This should print out the commands that you want to run!

find path -type d | awk '/[nN][0-9]+$/{original=$1; sub (/\/[nN][0-9]+$/,""); root= $1; $1=original; sub (/.*\/[nN]/,"/Nordic"); print "mv " original " " root $1;}'

If it doesn't then it will need a little tweaking? Once the commands output are exactly what you want to run, then AND ONLY THEN pipe then through to /bin/bash as detailed in the original line:)

LVL 22

Expert Comment

ID: 11806084
find path -type d | awk '/[nN][0-9]+$/{a=$1; sub (/\/[nN][0-9]+$/,""); b= $1; $1=a; sub (/.*\//,"/Nordic"); print "mv " a " " b $1;}' | /bin/bash

looks a little shorter, but is probably less easy to read?
LVL 23

Expert Comment

ID: 11806130
> looks a little shorter, but is probably less easy to read?

But it is not as short as the following (which uses two fewer processes):

for f in `find . -name "[nN][0-9]*" -a -type d -a -maxdepth 1` ; do mv $f ${f/^[nN]/Nordic} ; done

LVL 22

Expert Comment

ID: 11806283
Yep - I'll go with that. It is shorter. I also had a little grief trying to find a sensible way to deal with substituting a string within awk, and guaranteeing that it only swapped the name correctly.

You've used fewer processes, because you don't check for all alternatives. As a result yours needs altering a bit:

for f in `find . -name "[nN][0-9]*" -a -type d -a -maxdepth 1` ; do mv $f ${f/^[nN]/Nordic} ; done

will change any directory name containing an n or N!.(* is 0 or more occurances)........and I probably need to think a little more about your mv statement for folders such as ./nNnn89n. If there are only files of the form n123 etc, then you shouldn't have a problem. But what if additional folders are added after the conversion?

Also, it doesn't have the convenience of being able to view the output first in a very simple way before committing yourself to it. I originally considered a similar approach to yours, but I also got in a mess with the substitution. I'm sure that it should be possible, but I spend a couple of hours playing with it and couldn't get anything that I was really happy with.

As long as the provisos above apply then your script is fine...I've just tried to tie things down a little more. I think mine copes with most wierd variations...but I couldn't guarantee it......hence the view before running!

LVL 23

Expert Comment

ID: 11806701
> will change any directory name containing an n or N!.(* is 0 or more occurances)...

Actually that is not true in filename globbing (not quite true regular expressions).  
[nN][0-9]* matches any filename whose first character is n or N, second character
is a digit, and any number of characters after that.  
So it matches, n123, n1, N567JAZZ, but does not match nx123, number, .n234, or ñ123

>  Also, it doesn't have the convenience of being able to view the output first in a very
> simple way before committing yourself to it.

I simply add  'echo' between 'do' and 'mv'.  This prints out the move commands it would execute otherwise:
for f in `find . -name "[nN][0-9]*" -a -type d -a -maxdepth 1` ; do echo mv $f ${f/^[nN]/Nordic} ; done
That is how I tested the command as I refined it.   Occasionally, when answering these questions,
I forget to remove the 'echo' before pasting the command into the comment.

You can also run the find command on its own to see which directory names it collects.
That is how I build up these compound one-line programs - one segment at a time.

LVL 22

Expert Comment

ID: 11807580
That's the great delight of shell scripting. Loads of different ways to do it:)

Sorry if I got the matching slightly wrong for your setup, but it does still leave n5jazz, with all the other endings. Late night, and I'd been fighting to get a suitably short regex for about half an hour!  ..and yep the echo approach is nice.


Author Comment

ID: 11809683
Thanks for the assistance thus far... though even using copy/paste, and I still getting the folowoing response.  Please see below:

[vhs@s2 Test]$ for f in `find . -name "[nN][0-9]*" -a -type d -a -maxdepth 1` ; do echo mv $f ${f/^[nN]/Nordic} ; done
find: invalid expression
[vhs@s2 Test]$

Any idea as to why the command is not working for me?  I even removed the "echo" and received the same error.  

All help is appreciated!
LVL 23

Expert Comment

ID: 11811718
> Any idea as to why the command is not working for me?  I even removed the "echo" and received the same error.

First you need to learn to understand the commands used.  

1)  for f in [list] ; do [command] ; done
For each item f in the list, perform the command.

2) `find . -name "[nN][0-9]*" -a -type d -a -maxdepth 1`
This is the [list].  By enclosing the command in backquotes, the shell executes
the find command and populates [list] with the output.  The find command
is looking for files that satisfy 3 criteria (ANDed together with -a):
  a) filename starts with n or N, followed by a digit, followed by anything else ( -name "[nN][0-9]*" )
  b) file is a directory ( -type d )
  c) file is in current directory, not a subdirectory ( . and -maxdepth 1 )

3) mv $f ${f/^[nN]/Nordic}
This is the [command] from 1).  The first parameter is one if the items from [list].
The second parameter is the result of bash string substitution (substitute the n or N
at the beginning of f with Nordic.  When you prepend 'echo' to the command, echo
becomes the new command, with its 3 parameters:
  a) the string 'mv'
  b) the source filename
  c) the destination filename
And of course the echo command simply prints the three parameters out to the console.

So now you can see why changing the command in 3) has absolutely no impact on the execution
of `find ...` to build the list in 2)

I am using Mac OS X, which implements the FreeBSD version of the find command.
Linux uses the GNU fileutils version of the find command which might have a slightly
different syntax.  Check the man pages looking for differences in the syntax of the
three criteria used (2a, 2b, 2c, and '-a'):
  man 1 find

Author Comment

ID: 11812458
Actually, thanks for the response and helping me with the syntax.  Although I understood that portion, it was definitely nice to have it spelled out in such a manner.

I believe the actual issue that I am having is with the version of the find command.  I am not on a Mac OS... so I believe there may lie my issue.

Where can I find these "man pages" which you referenced?  Please advise.

LVL 23

Expert Comment

ID: 11813188
The man pages are usually installed in a path (like the executables they document),
typically /usr/man, /usr/local/man, etc. They are accessable by the 'man' commnad.

Like I mentioned in the previous post, run 'man 1 find' to search for the documentation
for 'find' in section 1 (shell commands) of the man pages.

For more information on man and man pages, run the command 'man man'.


Expert Comment

ID: 12165310
Not only is using 'find' a bit overblown, but I suspect 'for f in [list]' fries if no files are found.   I would check it, but I only
get to play with µSoft at work.

Accepted Solution

Computer101 earned 0 total points
ID: 12243973
PAQed - no points refunded (of 250)

E-E Admin

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Have you ever been frustrated by having to click seven times in order to retrieve a small bit of information from the web, always the same seven clicks, scrolling down and down until you reach your target? When you know the benefits of the command l…
The purpose of this article is to demonstrate how we can upgrade Python from version 2.7.6 to Python 2.7.10 on the Linux Mint operating system. I am using an Oracle Virtual Box where I have installed Linux Mint operating system version 17.2. Once yo…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit If you want to manage em…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

730 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question