# Quick Unix scripting question

**URL:** <https://boards.straightdope.com/t/quick-unix-scripting-question/423672>\
**Category:** In My Humble Opinion\
**Created:** [October 23, 2007, 5:24am UTC](https://boards.straightdope.com/t/quick-unix-scripting-question/423672 "2007-10-23T05:24:10Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![waterj2](https://avatars.discourse-cdn.com/v4/letter/w/858c86/32.png) [@waterj2](https://boards.straightdope.com/u/waterj2)\
**Post date:** [October 23, 2007, 5:24am UTC](https://boards.straightdope.com/t/quick-unix-scripting-question/423672/1 "2007-10-23T05:24:10Z")

</div>

This doesn’t seem really up the standards of GQ, and I’m sure there is more than one approach, so IMHO seems like a good place for it.

OK, basically, I want to take a file containing a .m3u playlist, which is simply a text file with the full path for each file on each line, and copy all the songs in it to a new directory. Ideally, I could rename each song to reflect its position in the playlist; even simply renaming them to 1.mp3, 2.mp3, etc. would work for me. Actually, most files are in .ogg format, and I do need it to preserve the extension, and, of course, Unix (OK, well, Linux in this case) permits pretty much any character in a file name other than the newline character, and a good number of odd characters may be used, but file name _can_ be guaranteed to end in either “.mp3” or “.ogg”.

There has to be some sort of simple solution to this, but Ubuntu’s been pretty smooth and I’m not used to doing anything complex from the command line these days. It also seems like the sort of thing that Perl or some other scripting language could handle easily, and I think I could figure things out enough to get that to work.

So, please, fire away with your ideas. Any help is appreciated.

---

<div class="post-metadata">

**Author:** ![brendon\_small](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/brendon_small/32/17101_2.png) [@brendon\_small](https://boards.straightdope.com/u/brendon_small)\
**Post date:** [October 23, 2007, 6:16am UTC](https://boards.straightdope.com/t/quick-unix-scripting-question/423672/2 "2007-10-23T06:16:31Z")

</div>

No answer here, but I look forward to some solutions. I just switched to Linux recently and have been trying to learn all I can about it.

Thanks for the interesting thread - I hope there are some good responses.

Brendon Small

---

<div class="post-metadata">

**Author:** ![friedo](https://avatars.discourse-cdn.com/v4/letter/f/8edcca/32.png) [@friedo](https://boards.straightdope.com/u/friedo)\
**Post date:** [October 23, 2007, 7:30am UTC](https://boards.straightdope.com/t/quick-unix-scripting-question/423672/3 "2007-10-23T07:30:19Z")

</div>

Here’s a completely untested Perl script which I think will do what you want.

```auto

#!/usr/bin/perl

use strict;
use warnings;

use File::Copy;

# target directory: 
my $target_dir = '/path/to/where/we/want/to/copy/them/to';

# first open the playlist file
open my $pfh, '/path/to/playlist/file.m3u' or die "Can't open playlist file: $!";

# loop over playlist line by line
while( <$pfh> ) { 
    chomp;
    my $dest = $target_dir . '/' . $_; # new filename
    print "$_ -> $dest
";
    copy $_, $dest or die "Can't copy file $_ to $dest: $!";
}

print "done.
";

```

ETA: That script assumes the filenames in the .m3u file are just plain filenames without their full path attached. If you need to extract the individual filenames, try using the [File::Basename](http://search.cpan.org/~nwclark/perl-5.8.8/lib/File/Basename.pm) module. It’s easier and works better than doing it with regexes.

---

<div class="post-metadata">

**Author:** ![Small\_Clanger](https://avatars.discourse-cdn.com/v4/letter/s/9fc348/32.png) [@Small\_Clanger](https://boards.straightdope.com/u/Small_Clanger)\
**Post date:** [October 23, 2007, 2:50pm UTC](https://boards.straightdope.com/t/quick-unix-scripting-question/423672/4 "2007-10-23T14:50:56Z")

</div>

```auto

{
while read fname; do
echo moving $fname
cp $fname /home/waterj2/music
done
} < musicfilelist.txt 

```

Obviously change the file name and directory. Renaming the files will involve some text replacement and since I’m not being paid for this I think I’ll stop here 🙂

---

<div class="post-metadata">

**Author:** ![Derleth](https://avatars.discourse-cdn.com/v4/letter/d/b9e5f3/32.png) [@Derleth](https://boards.straightdope.com/u/Derleth)\
**Post date:** [October 23, 2007, 3:12pm UTC](https://boards.straightdope.com/t/quick-unix-scripting-question/423672/5 "2007-10-23T15:12:59Z")

</div>

All these solutions expect that an m3u file is just a list of mp3 file names, like so:

```auto

One Toke Over The Line.mp3
Only The Lonely.mp3
Creep.mp3
Beware The Blob.mp3

```

If there is any more text in the file, the solutions will fail because the file needs to be parsed and the mp3 filenames extracted. Parsing can be really, really simple or really, really complex or something in-between, but we need to see the file to know what has to be done.

**Small Clanger** , will your solution work if there are spaces or special characters in the file names?

---

<div class="post-metadata">

**Author:** ![Bytegeist](https://avatars.discourse-cdn.com/v4/letter/b/9dc877/32.png) [@Bytegeist](https://boards.straightdope.com/u/Bytegeist)\
**Post date:** [October 23, 2007, 3:21pm UTC](https://boards.straightdope.com/t/quick-unix-scripting-question/423672/6 "2007-10-23T15:21:24Z")

</div>

Assuming you’re using **bash** , try this . . .

```auto

typeset -i n=1
cat FILE_LIST.m3u | while read fpath; do
  ext="${fpath##*.}"
  cp "$fpath" DESTINATION/$n.$ext
  let n+=1
done

```

Substitute for the capitalized symbols as appropriate.

---

<div class="post-metadata">

**Author:** ![Small\_Clanger](https://avatars.discourse-cdn.com/v4/letter/s/9fc348/32.png) [@Small\_Clanger](https://boards.straightdope.com/u/Small_Clanger)\
**Post date:** [October 23, 2007, 4:06pm UTC](https://boards.straightdope.com/t/quick-unix-scripting-question/423672/7 "2007-10-23T16:06:30Z")

</div>

[QUOTE=Derleth]  
**Small Clanger** , will your solution work if there are spaces or special characters in the file names?  
[/QUOTE]  
Probably not, it’s pretty brittle.

OK, tried it with spaces and it didn’t like them, bit of a shortcoming that. I guess _read_ pulls off the first word of the name. It’s probably possible to get round that with the right sort of quotes, hmm.

To cope with spaces change the copy line to this:

```auto

cp "$fname" /home/waterj2/music

```

---

<div class="post-metadata">

**Author:** ![Bytegeist](https://avatars.discourse-cdn.com/v4/letter/b/9dc877/32.png) [@Bytegeist](https://boards.straightdope.com/u/Bytegeist)\
**Post date:** [October 23, 2007, 5:07pm UTC](https://boards.straightdope.com/t/quick-unix-scripting-question/423672/8 "2007-10-23T17:07:28Z")

</div>

[QUOTE=Small Clanger]  
I guess _read_ pulls off the first word of the name. It’s probably possible to get round that with the right sort of quotes, hmm.

[/quote]

Your _read_ is fine. It actually does pull the entire line into the variable. It’s the absence of quotes around your _$fname_ in the copy command that breaks it when there are spaces.

> [@](#):
>
> To cope with spaces change the copy line to this:
> 
> ```auto
> 
> cp "$fname" /home/waterj2/music
> 
> ```

. . . And that fixes that.

---

<div class="post-metadata">

**Author:** ![black\_rabbit](https://avatars.discourse-cdn.com/v4/letter/b/f19dbf/32.png) [@black\_rabbit](https://boards.straightdope.com/u/black_rabbit)\
**Post date:** [October 23, 2007, 8:40pm UTC](https://boards.straightdope.com/t/quick-unix-scripting-question/423672/9 "2007-10-23T20:40:35Z")

</div>

[QUOTE=Bytegeist]  
Assuming you’re using **bash** , try this . . .

```auto

  ext="${fpath##*.}"

```

[/QUOTE]

Showoff. But you lose points on the unnecessary use of cat. 🙂

```auto

while read FILE; do
   cp "$FILE" "${i:=1}.${FILE##*.}"
   ((i++))
done < list.txt

```
