LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - General
User Name
Password
Linux - General This Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.

Notices


Reply
  Search this Thread
Old 06-15-2012, 05:39 PM   #1
rootaccess
Member
 
Registered: Mar 2012
Posts: 311

Rep: Reputation: Disabled
How to add leading zeros to numbers for file names


Hi everyone. I basically have a lot of files that look like this:

1) file_4_name.txt
2) file_40_name.txt
3) file _145_name.txt

I basically would like to add zeros before the 1st and 2nd set of numbers but not the 3rd since they already contain 3 digits. I'd like them all to be 3 digits, so two zeros should be added to the 1st set and one zero should be added to the 2nd set. I am not necessarily wanting to add the zeros to the very beginning of the file. Just before the corresponding numbers.

I'd like to get them to look like this:

1) file_004_name.txt
2) file_040_name.txt

Every set contains '_' before and after. Any help would be much appreciated. My limited use of awk and sed isn't helping much.

Thanks,
Shawn

Last edited by rootaccess; 06-15-2012 at 05:41 PM.
 
Old 06-15-2012, 06:25 PM   #2
pixellany
LQ Veteran
 
Registered: Nov 2005
Location: Annapolis, MD
Distribution: Mint
Posts: 17,809

Rep: Reputation: 743Reputation: 743Reputation: 743Reputation: 743Reputation: 743Reputation: 743Reputation: 743
Not tested (I'm eating dinner..... )

Code:
In a loop, reading files one at a time--putting the names into the variable "filename":
    newname=$(sed -r -e 's/_([0-9])_/_00\1/' -e 's/_([0-9]{2})_/_0\1_/' $filename)
    mv $filename $newname
continue loop
I'll test this shortly---unless someone beats me to it.....

UPDATE===this has problems, but I think the SED logic is maybe OK

For starters, it needs to be "echo $filename | sed .....etc"

Last edited by pixellany; 06-15-2012 at 07:07 PM. Reason: fixed an error
 
Old 06-15-2012, 06:32 PM   #3
TobiSGD
Moderator
 
Registered: Dec 2009
Location: Germany
Distribution: Whatever fits the task best
Posts: 17,148
Blog Entries: 2

Rep: Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886
Try it with the rename command. This excerpt from its man-page should fit to your case:
Quote:
SYNOPSIS
rename from to file...
rename -V

DESCRIPTION
rename will rename the specified files by replacing the first occurrence of from in their name by to.

-V, --version
Display version information and exit.

For example, given the files
foo1, ..., foo9, foo10, ..., foo278, the commands

rename foo foo0 foo?
rename foo foo0 foo??

will turn them into foo001, ..., foo009, foo010, ..., foo278.
So in your case it should be:
Code:
rename file_ file_0 file_?_name.txt
rename file_ file_0 file_??_name.txt
 
Old 06-15-2012, 07:24 PM   #4
rootaccess
Member
 
Registered: Mar 2012
Posts: 311

Original Poster
Rep: Reputation: Disabled
The rename command did not seem to work. Are you sure it is 3 separate fields?

Quote:
Originally Posted by TobiSGD View Post
Try it with the rename command. This excerpt from its man-page should fit to your case:So in your case it should be:
Code:
rename file_ file_0 file_?_name.txt
rename file_ file_0 file_??_name.txt
 
Old 06-15-2012, 07:54 PM   #5
TobiSGD
Moderator
 
Registered: Dec 2009
Location: Germany
Distribution: Whatever fits the task best
Posts: 17,148
Blog Entries: 2

Rep: Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886
Yes, the syntax is
Code:
rename from tofiles
Where from is the part you want to replace with to in files.
Therefore there are two replacements, in the first part all files that have only one digits in the name (file_?_name.txt) get the part file_ replaced with file_0 (for example file_1_name.txt -> file_01_name.txt).
In the second replacement all files with two digits in the name (file_??_name.txt) get the part file_ also replaced with file_0 (for example file_01_name.txt -> file_001_name.txt).
Quite simple once you grasp the concept, it took me some time.
 
Old 06-15-2012, 08:54 PM   #6
rootaccess
Member
 
Registered: Mar 2012
Posts: 311

Original Poster
Rep: Reputation: Disabled
Ok I deliberately made a file called file_1_name.txt and used

Code:
rename file_ file_0 file_?_name.txt
This is the error I get
Code:
Bareword "file_" not allowed while "strict subs" in use at (eval 1) line 1.

Quote:
Originally Posted by TobiSGD View Post
Yes, the syntax is
Code:
rename from tofiles
Where from is the part you want to replace with to in files.
Therefore there are two replacements, in the first part all files that have only one digits in the name (file_?_name.txt) get the part file_ replaced with file_0 (for example file_1_name.txt -> file_01_name.txt).
In the second replacement all files with two digits in the name (file_??_name.txt) get the part file_ also replaced with file_0 (for example file_01_name.txt -> file_001_name.txt).
Quite simple once you grasp the concept, it took me some time.
 
Old 06-15-2012, 09:07 PM   #7
dru8274
Member
 
Registered: Oct 2011
Location: New Zealand
Distribution: Debian
Posts: 105

Rep: Reputation: 37
I believe that formatting with printf can give you leading zeroes, as described here. I use a small function in my scripts for this. A small example:-
Code:
$ # to print an index-number-- an integer padded with preceding zeroes. 
$ # $1 = number of digits   $2 = number to print
$ function idxnum() { printf "%0${1}d" "$2" ; }

$ numx=40
$ echo file_$(idxnum 3 $numx)_name.txt
file_040_name.txt

Last edited by dru8274; 06-15-2012 at 09:13 PM.
 
Old 06-15-2012, 09:08 PM   #8
TobiSGD
Moderator
 
Registered: Dec 2009
Location: Germany
Distribution: Whatever fits the task best
Posts: 17,148
Blog Entries: 2

Rep: Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886
That is strange, I just tested it on Slackware 13.37 32 bit:
Code:
tobi@dragon ~/test :) % touch file_1_name.txt
tobi@dragon ~/test :) % rename file_ file_0 file_?_name.txt
tobi@dragon ~/test :) % ls
file_01_name.txt
Works fine here.

EDIT: May it be possible that you run Debian or a derived distro? Seems that they have a different version of the rename command which needs a Perl regular expression: http://tips.webdesign10.com/how-to-b...n-the-terminal

Last edited by TobiSGD; 06-15-2012 at 09:12 PM. Reason: added info
 
Old 06-15-2012, 10:57 PM   #9
rootaccess
Member
 
Registered: Mar 2012
Posts: 311

Original Poster
Rep: Reputation: Disabled
I do have debian and that link is in reference to Debian distros so I dont understand why it isn't working on my end.

Quote:
Originally Posted by TobiSGD View Post
That is strange, I just tested it on Slackware 13.37 32 bit:
Code:
tobi@dragon ~/test :) % touch file_1_name.txt
tobi@dragon ~/test :) % rename file_ file_0 file_?_name.txt
tobi@dragon ~/test :) % ls
file_01_name.txt
Works fine here.

EDIT: May it be possible that you run Debian or a derived distro? Seems that they have a different version of the rename command which needs a Perl regular expression: http://tips.webdesign10.com/how-to-b...n-the-terminal
 
Old 06-15-2012, 11:26 PM   #10
rootaccess
Member
 
Registered: Mar 2012
Posts: 311

Original Poster
Rep: Reputation: Disabled
Ok I made a script and put this in there

Code:
#!/bin/bash
function idxnum() { printf "%0${1}d" "$2" ; }

numx=40
echo php_$(idxnum 3 $numx)_tut.mp4
when I executed the script, it printed php_040_tut.mp4 so we're getting somewhere but how would I actually mv that file to make the changes instead of just printing it? Would I use xargs mv?

I'm trying to rename a massive amount of files. not just _40_ ...
I would like to rename 20 to 020, 68 to 068, 7 to 007, etc.
What kind of value would I use for the numx variable to call 2 characters? I tried ?? but I guess that won't work. Still trying to figure out this printf stuff. Never thought you could make a function like that. Strange things occur in linux, but that's what's great about it.



Quote:
Originally Posted by dru8274 View Post
I believe that formatting with printf can give you leading zeroes, as described here. I use a small function in my scripts for this. A small example:-
Code:
$ # to print an index-number-- an integer padded with preceding zeroes. 
$ # $1 = number of digits   $2 = number to print
$ function idxnum() { printf "%0${1}d" "$2" ; }

$ numx=40
$ echo file_$(idxnum 3 $numx)_name.txt
file_040_name.txt
 
Old 06-15-2012, 11:51 PM   #11
dru8274
Member
 
Registered: Oct 2011
Location: New Zealand
Distribution: Debian
Posts: 105

Rep: Reputation: 37
Quote:
Originally Posted by rootaccess View Post
What kind of value would I use for the numx variable to call 2 characters?
The first parameter to idxnum defines the number of digits. Whereas the second parm is the index number we want to print. So for example, "40" can be printf here with padded zeroes, using 4 digits, 6 digits, and 9 digits...

Code:
$ idxnum 4 40
0040
$ idxnum 6 40 
000040
$ idxnum 9 40
000000040
Quote:
Originally Posted by rootaccess View Post
but how would I actually mv that file to make the changes instead of just printing it?
Try this please. I've assumed here that the number is always delimited by "_" chars, as you mentioned above. And I've commented out the move command, so you can check that the file renaming is working okay first.

Code:
function idxnum() { printf "%0${1}d" "$2" ; }

for filex in * ; do
    numx="${filex#*_}"
    numx="${numx%_*}"
    echo "$filex   ${filex%%_*}_$(idxnum 3 $numx)_${filex##*_}"
    # mv -v "$filex" "${filex%%_*}_$(idxnum 3 $numx)_${filex##*_}"
done

Last edited by dru8274; 06-16-2012 at 03:07 AM. Reason: extra explanation for idxnum
 
Old 06-16-2012, 03:16 AM   #12
rootaccess
Member
 
Registered: Mar 2012
Posts: 311

Original Poster
Rep: Reputation: Disabled
Ok I made 3 test files using php_2_tut.mp4 and it worked for that, but when I tried using it for the real files, they wouldnt work because I have more than just 3 total fields between underscores. And I do see in the script that it is meant for 3 fields but how would I get it to work with any amount of fields, be it 2 fields or 9 between underscores. Let me explain.

The real files vary. They look like this:
beginner_php_tutorial_1_introduction_to_php.mp4
beginner_php_tutorial_30_basic_functions.mp4
beginner_php_tutorial_33_global_variables_and_functions.mp4
beginner_php_tutorial_174_loading_in_file_contents_to_a_div_part_3.mp4

So as you can see, there could be 3 fields after the number 1, and 9 fields after the 174th video.

How would I change the script to correspond with that?
Otherwise it works on files like this:
php_7_tut.mp4
which then became php_007_tut.mp4

I should have been more clear from the very beginning. I have to remember everything is very literal and counts. Sorry for that.



Quote:
Originally Posted by dru8274 View Post
The first parameter to idxnum defines the number of digits. Whereas the second parm is the index number we want to print. So for example, "40" can be printf here with padded zeroes, using 4 digits, 6 digits, and 9 digits...

Code:
$ idxnum 4 40
0040
$ idxnum 6 40 
000040
$ idxnum 9 40
000000040


Try this please. I've assumed here that the number is always delimited by "_" chars, as you mentioned above. And I've commented out the move command, so you can check that the file renaming is working okay first.

Code:
function idxnum() { printf "%0${1}d" "$2" ; }

for filex in * ; do
    numx="${filex#*_}"
    numx="${numx%_*}"
    echo "$filex   ${filex%%_*}_$(idxnum 3 $numx)_${filex##*_}"
    # mv -v "$filex" "${filex%%_*}_$(idxnum 3 $numx)_${filex##*_}"
done

Last edited by rootaccess; 06-16-2012 at 03:17 AM.
 
Old 06-16-2012, 05:13 AM   #13
dru8274
Member
 
Registered: Oct 2011
Location: New Zealand
Distribution: Debian
Posts: 105

Rep: Reputation: 37
Quote:
Originally Posted by rootaccess View Post
So as you can see, there could be 3 fields after the number 1, and 9 fields after the 174th video. How would I change the script to correspond with that?
Okay, so we need to craft ourselves a better rename script. So I've rewritten the rename script, totally different, and using "sed" to extract that number as exactly as poss, and to then rename and move the file.

I've commented it a bit, and added some color. And if the script can't extract a $numx from a filename, then it will print a warning message in red. But the script defaults to just printing out filenames, the original and the modified. And if that looks okay, then you can uncomment the mv command, and then run it again for effect.

Furthermore, the mv command will move the renamed files into a folder ./temp1. Such that after you run the script, the only files left in your current folder will be those files the script couldn't handle. That said, I think it will do the trick. So enuf said...

Code:
function idxnum() { printf "%0${1}d" "$2" ; }

# Color codes
bold="$(tput bold)"     # bold text
grn="$(tput setaf 2)"   # green text
normal="$(tput sgr0)"   # normal text

mkdir temp1 2>/dev/null
for filex in *_[0-9]* ; do
    # use sed to extract just the number embedded in the filename
    numx="$(echo $filex | sed -n 's/^.*_\([0-9]\+\)_.*$/\1/p')"

    # if a valid numx wasn't found then move onto next file. Print a warning in RED!
    if      [[ ! $numx =~ ^[0-9]+$ ]]
    then    echo -e "${bold}$(tput setaf 1)FAIL : ${filex}${normal}" && continue
    fi

    # substitute and replace $numx with an idxnum number. This sed doesn't need quotes.
    filev="$(echo $filex | sed s/_${numx}_/_$(idxnum 3 $numx)_/)"

    # print to stdout the original and modified filenames.
    echo -e "${grn}${filex}${normal}\t\t${bold}${filev}${normal}"

    # move filex to new filename filev, and place into ./temp1.
    #mv "$filex" "./temp1/$filev"
done
 
Old 06-16-2012, 06:04 AM   #14
TobiSGD
Moderator
 
Registered: Dec 2009
Location: Germany
Distribution: Whatever fits the task best
Posts: 17,148
Blog Entries: 2

Rep: Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886Reputation: 4886
Quote:
Originally Posted by rootaccess View Post
I do have debian and that link is in reference to Debian distros so I dont understand why it isn't working on my end.
Of course is the link for Debian distros. Didi you actually read what was written there? As the link states, Debian (and derivatives) have for some reason a version with a different syntax. The syntax I gave you won't work, you have to use Perl regular expressions for it. Since I am bad with those expressions I can't help you with that, but I would guess that something like
Code:
rename ´s/file_/file_0/´ file_?_name.txt
will work (for the first part.
 
Old 06-16-2012, 12:34 PM   #15
rootaccess
Member
 
Registered: Mar 2012
Posts: 311

Original Poster
Rep: Reputation: Disabled
holy hell! That script looks like something from hell but it worked like a charm. I think it would take me a couple months just to try to decipher it!

Anyway, I altered it a bit and just commented out the mkdir temp and when moving I removed the dir only because I need the files to stay in the same directory but I thank you very very much for your help. You're a GENIUS.

Quote:
Originally Posted by dru8274 View Post
Okay, so we need to craft ourselves a better rename script. So I've rewritten the rename script, totally different, and using "sed" to extract that number as exactly as poss, and to then rename and move the file.

I've commented it a bit, and added some color. And if the script can't extract a $numx from a filename, then it will print a warning message in red. But the script defaults to just printing out filenames, the original and the modified. And if that looks okay, then you can uncomment the mv command, and then run it again for effect.

Furthermore, the mv command will move the renamed files into a folder ./temp1. Such that after you run the script, the only files left in your current folder will be those files the script couldn't handle. That said, I think it will do the trick. So enuf said...

Code:
function idxnum() { printf "%0${1}d" "$2" ; }

# Color codes
bold="$(tput bold)"     # bold text
grn="$(tput setaf 2)"   # green text
normal="$(tput sgr0)"   # normal text

mkdir temp1 2>/dev/null
for filex in *_[0-9]* ; do
    # use sed to extract just the number embedded in the filename
    numx="$(echo $filex | sed -n 's/^.*_\([0-9]\+\)_.*$/\1/p')"

    # if a valid numx wasn't found then move onto next file. Print a warning in RED!
    if      [[ ! $numx =~ ^[0-9]+$ ]]
    then    echo -e "${bold}$(tput setaf 1)FAIL : ${filex}${normal}" && continue
    fi

    # substitute and replace $numx with an idxnum number. This sed doesn't need quotes.
    filev="$(echo $filex | sed s/_${numx}_/_$(idxnum 3 $numx)_/)"

    # print to stdout the original and modified filenames.
    echo -e "${grn}${filex}${normal}\t\t${bold}${filev}${normal}"

    # move filex to new filename filev, and place into ./temp1.
    #mv "$filex" "./temp1/$filev"
done
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Renaming files (adding leading zeros) General Linux - Software 3 01-09-2011 09:17 AM
how to add numbers in a formatted file via a bash script? zero79 Linux - General 8 12-24-2010 05:48 PM
Need a script to find/replace numbers with names in 1 file using another as the guide kmkocot Programming 4 07-03-2009 03:30 AM
In Python, printing leading zero for hex numbers 0 through f donpar Programming 1 04-15-2009 07:09 PM
Add consecutive numbers to a Chinese file tcma Linux - General 0 10-19-2004 03:25 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - General

All times are GMT -5. The time now is 08:41 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration