...making Linux just a little more fun!
Ben Okopnik [ben at linuxgazette.net]
This comes up occasionally: you have a numbered list of files and you need to reorganize them, say by moving all the numbers up two places to accomodate two more files being added to the "front of the queue", or inserted in the middle of it. Even if you're familiar with loops, the answers aren't quite as simple as "loop over the numbers, add 2, and rename": doing so would overwrite the third file with the first one, the fourth one with the second one, and so on. Ugh, what a mess!
Here's the general form of an approach that'll work well:
start=0 # Lowest number in the list end=10 # Highest number in the list incr=2 # The increment for n in $(seq $start $end|tac); do mv $n $(($n + $incr)); done
Since piping the list through 'tac' will invert it, we will now be renaming the files in reverse order - that is, 10->12, 9->11, 8->10, and so on - which will prevent the above collisions. Renaming files that have numbers as part of the name isn't much more difficult: given, say, 'File1xyz.txt' and so on, the loop body simply becomes
for n in $(seq $start $end|tac) do mv File${n}xyz.txt File$(($n + $incr))xyz.txt done
Bonus feature: if you have a list of numbers that goes over 9 (or 99), and you want it sorted numerically (rather than '1 10 11 12 2 3 ...'), just use 'printf' to format the second parameter:
for n in $(seq $start $end|tac) do mv $n $(printf '%02d' $(($n + $incr))) done
The '02' in the above will result in numbers that are always 2 digits long, by prefixing the single-digit ones with a zero. Obviously, this can be extended to whatever number of digits is desired - and 'ls' will now show a properly numerically-sorted list.
-- * Ben Okopnik * Editor-in-Chief, Linux Gazette * http://LinuxGazette.NET *
Neil Youngman [ny at youngman.org.uk]
On Thursday 19 August 2010 01:01:52 Ben Okopnik wrote:
> ``` > start=0?????????# Lowest number in the list > end=10??????????# Highest number in the list > incr=2??????????# The increment > for n in $(seq $start $end|tac); do mv $n $(($n + $incr)); done > ''' > > Since piping the list through 'tac' will invert it, we will now be > renaming the files in reverse order - that is, 10->12, 9->11, 8->10, > and so on - which will prevent the above collisions.
Nice, but the pipe to 'tac' isn't really necessary '$(seq $end -1 $start)' will do just as well.
Neil
Ben Okopnik [ben at linuxgazette.net]
On Thu, Aug 19, 2010 at 10:05:33AM +0100, Neil Youngman wrote:
> On Thursday 19 August 2010 01:01:52 Ben Okopnik wrote: > > ``` > > start=0?????????# Lowest number in the list > > end=10??????????# Highest number in the list > > incr=2??????????# The increment > > for n in $(seq $start $end|tac); do mv $n $(($n + $incr)); done > > ''' > > > > Since piping the list through 'tac' will invert it, we will now be > > renaming the files in reverse order - that is, 10->12, 9->11, 8->10, > > and so on - which will prevent the above collisions. > > Nice, but the pipe to 'tac' isn't really necessary '$(seq $end -1 $start)' > will do just as well.
Oh, cool - I've been usng 'seq' for years, and didn't know it could do that. Thanks!
-- * Ben Okopnik * Editor-in-Chief, Linux Gazette * http://LinuxGazette.NET *