2

Possible Duplicate:
makefile: how to add a prefix to the basename?

I have a lit of files (which I get from find bla -name "*.so") such as:

/bla/a1.so /bla/a2.so /bla/blo/a3.so /bla/blo/a4.so /bla/blo/bli/a5.so

and I want to rename them such as it becomes:

/bla/liba1.so /bla/liba2.so /bla/blo/liba3.so /bla/blo/liba4.so /bla/blo/bli/liba5.so

... i.e. add the prefix 'lib' to the basename

any idea on how to do that in bash ?

Community
  • 1
  • 1
dm76
  • 4,130
  • 8
  • 35
  • 46

6 Answers6

7

Something along the lines of:

for a in /bla/a1.so /bla/a2.so /bla/blo/a4.so
do
  dn=$(dirname $a)
  fn=$(basename $a)
  mv "$a" "${dn}/lib${fn}"
done

should do it. You might want to add code to read the list of filenames from a file, rather than listing them verbatim in the script, of course.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
unwind
  • 391,730
  • 64
  • 469
  • 606
6
find . -name "*.so" -printf "mv '%h/%f' '%h/lib%f'\n" | bash

The code will rename files in current directory and subdirectories to append "lib" in front of .so filenames.

No looping needed, as find already does its recursive work to list the files. The code builds the "mv" commands one by one and executes them. To see the "mv" commands without executing them, simply remove the piping to shell part "| bash".

find's printf command understands many variables which makes it pretty scalable. I only needed to use two here:

  • %h: directory
  • %f: filename

How to test it:

Run this first (will perform nothing yet, only print lines on the screen):

find . -name "*.so" -printf "mv '%h/%f' '%h/lib%f'\n" | less -S

This will show you all the commands that your script will execute. If you're satisfied with the result, simply execute it afterwards by piping it into bash instead of less.

find . -name "*.so" -printf "mv '%h/%f' '%h/lib%f'\n" | bash
Wadih M.
  • 12,810
  • 7
  • 47
  • 57
  • You might want to add an appropriate `mindepth` and `maxdepth` to the find command and protect the file and directory names with quotes in case they [shudder] have spaces in them. `find . -mindepth 2 -maxdepth 2 -name "*.so" -printf "mv '%h/%f' '%h/lib%f'\n" | sh` – Dennis Williamson Aug 24 '09 at 15:37
  • I agree for the quotes, i've updated my code in consequence. – Wadih M. Aug 24 '09 at 16:23
  • Does this solution have any problems with many results? eg. hitting max command length or anything like that? – Leonidas A Jun 16 '16 at 03:03
  • No because it would print it line by line. I've updated my answer to give a way to test it in a dry run. – Wadih M. Jun 16 '16 at 13:30
2

while multiliner

A slightly more robust and generalized solution based on $nfm (maybe more than you really need) would be

while IFS= read -r -u3 -d $'\0' FILE; do
    DIR=`dirname $FILE`;
    FILENAME=`basename $FILE`;
    mv $FILE ${DIR}/lib${FILENAME};
done 3< <(find bla -name *.so -print0 | sort -rz)

This is quite robust:

  • read -u3 and 3< does not interfere with stdin
  • -print0 + IFS= + -d $'/0' allows for newlines in filenames
  • sort -rz renames deeper paths first, so that you can even rename directories and the files inside them at once

find -execdir + rename

This would be perfect if it weren't for the PATH annoyances, see: Find multiple files and rename them in Linux

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
1

Try mmv:

cd /bla/
mmv "*.so" "lib#1.so"

(mmv "*" "lib#1" would also work but it's less safe).

If you don't have mmv installed, get it.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
0

basename and dirname are your friends :)

You want something like this (excuse my bash syntax - it's a little rusty):

for FILE in `find bla -name *.so` do
    DIR=`dirname $FILE`;
    FILENAME=`basename $FILE`;
    mv $FILE ${DIR}/lib${FILENAME};
done

Beaten to the punch!

nfm
  • 19,689
  • 15
  • 60
  • 90
0

Note I've commented out the mv command to prevent any accidental mayhem

for f in *
do
    dir=`dirname "$f"`
    fname=`basename "$f"`
    new="$dir/lib$fname"
    echo "new name is $new"
    # only uncomment this if you know what you are doing
    # mv "$f" "$new" 
done