LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Help with Bash Script - Rename Multiple Files (https://www.linuxquestions.org/questions/programming-9/help-with-bash-script-rename-multiple-files-347062/)

embsupafly 07-26-2005 04:48 PM

Help with Bash Script - Rename Multiple Files
 
Ok,

I am working on a bash script and I am in need of some major help if anyone is willing to assist!

We have a directory with about 17,000 image files in it. The image files are names in the format pic0001.eps, pic0002.eps, etc.. Each of these file names corresponds to a real name such as Red Cross, Sony, etc. What we have in addition to the files, is (1) in a large text file, a sorted alphabetical listing of all of the filenames, and (2) a seperate text file of the real names that the filenames are supposed to be that are listed in the same corresponding order as the text file with the filenames.

I am struggling to find a way to get a bash file to enter the directory with the image files and text files and look at the text file with the filenames, select this file and rename the file according to the real name associated with it in the other textfile with the real names while keeping the same file extention.

Anyone have ideas?

druuna 07-27-2005 11:04 AM

Hi,

If I understand correctly then this should do what you want:

Code:

#!/bin/bash

# sorted list with real file names
REALNAME="/path/to/sorted.real.names"

# list with wanted name
WANTEDNAME="/path/to/wanted.names"

# directory that holds pictures/files
PICDIR="/path/to/picture/directory"

sdiff -t ${REALNAME} ${WANTEDNAME} | \
sed 's/ [ ]*|  /|/' | \
 awk -v PICDIR=${PICDIR} -F"[.|]" '{ print "mv "PICDIR"/"$1"."$2" \""PICDIR"/"$3"."$2"\"" }' > /tmp/rename-this
. /tmp/rename-this

#sdiff -t ${REALNAME} ${WANTEDNAME} | sed 's/ [ ]*|  /|/' | \
#  awk -v PICDIR=${PICDIR} -F"[.|]" '{ print "mv "PICDIR"/"$1"."$2" \""PICDIR"/"$3"."$2"\"" }' | bash

A little breakdown of the above:

The first three variables (REALNAME, WANTEDNAME and PICDIR) need to point to the appropriate files/dirs. You need to change this before you start testing/trying.

sdiff -t ${REALNAME} ${WANTEDNAME} This merges the file holding the actual names with the file holding the wanted names. I do undestand that these files correspond, this needs to be so for the correct working of this 'script'.
The -t option expands tabs to spaces, which will make life a bit easier for what comes next.

Part of this output:
Code:

pic0001.esp                                                      |  Sony
pic0002.esp                                                      |  Red Cross

sed 's/ [ ]*| /|/' This replaces the 'middle part' (spaces | spaces) with just a |

Part of this output:
Code:

pic0001.esp|Sony
pic0002.esp|Red Cross

awk -v PICDIR=${PICDIR} -F"[.|]" '{ print "mv "PICDIR"/"$1"."$2" \""PICDIR"/"$3"."$2"\"" }'

LOL This might need a longer explenation all by it self, which I will not do.....

What it does? It creates a legal move statement (mv x y). It also surrounds both source and destination with double quotes (mv "x" "y"), this to take care of special chars (spaces being the obvious one).

Part of this output:
Code:

mv "/path/to/picture/directory/pic0001.esp" "/path/to/picture/directory/Sony.esp"
mv "/path/to/picture/directory/pic0002.esp" "/path/to/picture/directory/Red Cross.esp"

The script gives you 2 option to continue:

1The one that is 'active' at the moment ) Put the output in a file (/tmp/rename-this) and parse the file (. /tmp/rename-this).

2) pipe the output of the awk command to bash ( awk ... | bash).

I like the second one better.

Hope this gets you going again.

keefaz 07-27-2005 11:08 AM

I have a perl solution :
PHP Code:

#!/usr/bin/perl

my $dir '/path/to/images/directory';
my $names '/path/to/file/with/the/wanted/names';
my $files '/path/to/file/with/the/real/name';

chdir $dir or
    die 
"Could not change dir to $dir: $!\n";

open NAMES$names or die "Could not open $names: $!\n";

open FILES$files or die "Could not open $files: $!\n";

my $name = <NAMES>;
chomp $name;

my $file = <FILES>;
chomp $file;

while(
$name && $file) {
    print 
"renaming $file to $name...\n";
    
rename $file$name;
    
$name = <NAMES>;
    
chomp $name;
    
$file = <FILES>;
    
chomp $file;
}

close NAMES;
close FILES


druuna 07-27-2005 11:11 AM

@keefaz : Nice!

@embsupafly : Use keefaz' solution. Much more elegant and resource friendly.

williamharwell 02-15-2007 09:54 PM

Multiple dots in a file name
 
The first example works great on files with only one dot. Ex: picture1.jpg. But what if I need to do this on files with multiple dots such as picture.1.jpg

I would like to change the filename except for the final dot and extension.

Any ideas?

The second example written in Perl does not leave the extension intact.

Thanks

cfaj 02-18-2007 10:05 PM

Quote:

Originally Posted by embsupafly
Ok,

I am working on a bash script and I am in need of some major help if anyone is willing to assist!

We have a directory with about 17,000 image files in it. The image files are names in the format pic0001.eps, pic0002.eps, etc.. Each of these file names corresponds to a real name such as Red Cross, Sony, etc. What we have in addition to the files, is (1) in a large text file, a sorted alphabetical listing of all of the filenames, and (2) a seperate text file of the real names that the filenames are supposed to be that are listed in the same corresponding order as the text file with the filenames.

I am struggling to find a way to get a bash file to enter the directory with the image files and text files and look at the text file with the filenames, select this file and rename the file according to the real name associated with it in the other textfile with the real names while keeping the same file extention.

Anyone have ideas?

What do the text files contain?

Is there one file with the current file name and another with the new file name?

Is there a line-to-line correspondence between the files?

Do the files contain the full names of the files, or just the part before the suffix ("extension" in Windows-speak)?

I would use something like this, but without more details on the format of the files, I cannot tell whether it will work:

Code:

exec 3<textfile1
exec 4<textfile2
cd /path/to/directory/with/images
while read file <&3; read name <&4
do
  mv "$file" "$name"
done


nefg 03-22-2010 09:19 AM

It works
 
The solution given by cfaj works!


Code:

exec 3<textfile1
exec 4<textfile2
cd /path/to/directory/with/images
while read file <&3; read name <&4
do
mv "$file" "$name"
done

Thanks

grail 03-22-2010 10:03 AM

Assuming both files checked just place after name of script separated by space:

Code:

#!/usr/bin/awk -f

BEGIN{
        file1 = ARGV[1]
        file2 = ARGV[2]
}

NR{
        getline < file1
        out1 = $0
        getline < file2
        out2 = $0

        system("mv \"" out1 "\" \"" out2 "\"")
}


nefg 03-26-2010 10:18 AM

Thanks to "grail". This awk script works too. However the NR in the script seems to be reduntant i.e. it works without the NR in the script code. Also when executing either as an executable script or just code typed in fro command line it goes through the renaming sequence twice (it is harmless though)

grail 03-26-2010 10:36 AM

Yeah I am not sure what I was thinking there (looking back at it) :$
Although as I am still on the learning side of awk i have also discovered
the variable assignment can be done on one line too:

Code:

getline out1 < file1

nefg 03-29-2010 05:05 AM

Also ( I think) why it goes on repeating the "action" after renaming of files is completed, is because awk repeats the test for total nos lines of input. In this case two files are input. So it repeats for total nos lines for both files. The renaming is complete when it goes through the first file and balance actions are redundant. If you give it three parameters eg file1 file2 file2, it repeats action for total nos lines for all three files. This can be verified by adding

END{
print "NR is - " NR
}
at end of code.

Thanks and
Best Regards

grail 03-29-2010 08:53 AM

So like I said before ... always learning :)

Code:

#!/usr/bin/awk -f

BEGIN{
    file1 = ARGV[1]
    file2 = ARGV[2]
}

(getline out1 < file1) > 0{

    getline out2 < file2

    print | "mv \"" out1 "\" \"" out2 "\""
}

This stops when the first file runs out of lines :)

nefg 03-31-2010 05:16 AM

Thanks grail. You are a Master. Total problem solved.
Best Regards

grail 03-31-2010 06:58 AM

Can't keep a good man down (although I fear there are true gurus around who can do better):

Code:

#!/usr/bin/awk -f

ARGV[1] == FILENAME{

    getline out2 < ARGV[2]

    print "mv \"" $0 "\" \"" out2 "\""
}


nefg 04-01-2010 01:13 PM

Thanks to grail. It took time to "digest" the compact code. To work you have to add "|bash" to the end of the command however.
Best Regards


All times are GMT -5. The time now is 10:39 AM.