Solved

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

Posted on 2004-08-15
17
315 Views
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.
0
Comment
Question by:Jawanza
  • 6
  • 4
  • 3
  • +2
17 Comments
 
LVL 23

Expert Comment

by:brettmjohnson
Comment Utility
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

0
 

Author Comment

by:Jawanza
Comment Utility
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.
0
 
LVL 23

Expert Comment

by:brettmjohnson
Comment Utility
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.




0
 
LVL 22

Expert Comment

by:pjedmond
Comment Utility
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!


first:

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
original=$1

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:)

HTH:)
0
 
LVL 22

Expert Comment

by:pjedmond
Comment Utility
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?
0
 
LVL 23

Expert Comment

by:brettmjohnson
Comment Utility
> 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

0
 
LVL 22

Expert Comment

by:pjedmond
Comment Utility
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!

0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 23

Expert Comment

by:brettmjohnson
Comment Utility
> 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.








0
 
LVL 22

Expert Comment

by:pjedmond
Comment Utility
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.


0
 

Author Comment

by:Jawanza
Comment Utility
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!
0
 
LVL 23

Expert Comment

by:brettmjohnson
Comment Utility
> 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
0
 

Author Comment

by:Jawanza
Comment Utility
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.

Thanks,
0
 
LVL 23

Expert Comment

by:brettmjohnson
Comment Utility
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'.

0
 

Expert Comment

by:skewray
Comment Utility
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.
0
 
LVL 1

Accepted Solution

by:
Computer101 earned 0 total points
Comment Utility
PAQed - no points refunded (of 250)

Computer101
E-E Admin
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

The purpose of this article is to fix the unknown display problem in Linux Mint operating system. After installing the OS if you see Display monitor is not recognized then we can install "MESA" utilities to fix this problem or we can install additio…
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…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

744 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

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now