Question

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 ?

Was it helpful?

Solution

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.

OTHER TIPS

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

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

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.

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!

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top