2

I'm trying to move files like this:

...
DLG023-00-01-sprite.TextGrid.json
DLG023-00-01.prosody.json
DLG023-01-01-sprite.ogg
DLG023-00-02-sprite.TextGrid.json
DLG023-00-02.prosody.json
DLG023-01-02-sprite.ogg
...
DLG028-00-01-sprite.TextGrid.json
DLG028-00-01.prosody.json
DLG028-01-01-sprite.ogg
...

into their respective folders, e.g.: move the file to dialogue023/ when it starts with DLG023; to dialogue024/ when it starts with DLG024; and so on.

All of the files and directories are at the same level.

In other words, I'm trying to produce commands like this one:

mv DLG023-00-01-sprite.ogg dialogue023/

How can I extract the first number from the filename?

So far I've got this:

for i in DLG*-*-*-sprite.ogg; do echo "${i//[^0-9]}";done

But this outputs all of the digits (e.g.: 230001) when I only want the first one (e.g.: 23).

4
  • 1
    It doesn't actually extract the numbers, so it's not an answer to the question, but in principle you can also do something like for num in $(seq -f '%03g' 1 999); do test -d dialogue${num}||mkdir dialogue${num}; mv -t dialogue${num} DLG${num}-*; done followed by rmdir dialogue* -- the -f '%03g' means all numbers are zero-padded to at least three digits, and since 999 fits into three digits all numbers will become three digits long in the directory names. Plain rmdir fails if the directory is not empty, so is safe. Brace for unimportant error output from mv about nonexistent files.
    – user
    Commented May 29, 2015 at 12:28
  • Is it always chars 4-6?
    – Paul
    Commented May 29, 2015 at 13:25
  • Thank you Michael, that's the clever way to go about it. Commented May 29, 2015 at 16:55
  • It's always chars 3-6 (or 4-6 for now.) Commented May 29, 2015 at 16:55

4 Answers 4

1

I'm assuming that you are using OS X, which doesn't have the -t option in mv. This will be painfully slow if the script is processing thousands of files.

    for file in DLG*; do
    # Extract the three digits after DLG
    getnum=${file%%-*}
    getnum=${getnum#???}

    # make the directory dialogue### or exit if there is an error
    echo mkdir -p "dialogue${getnum}" || exit

    echo mv "$file" "dialogue${getnum}"
    done

Remove the echo before mkdir and mv if the output is satifactory.

2
  • Works like a charm. It does not happen in the blink of an eye but does happen in seconds for 19 folders. Out of sheer curiosity: is there a way to extract the three digits in just one step? Commented Jun 10, 2015 at 8:26
  • @Fabien Snauwaert- You could use substring expansion in one step instead of substring removal but substring expansion is not available in every shell.
    – fd0
    Commented Jun 10, 2015 at 16:17
0

You could generate the mv command using this:

for f in DLG*; do echo "$f" | sed 's/DLG\([0-9]\+\).*/mv "\0" "dialogue\1\/"/g'; done

Now, the command are printed like this:

mv "DLG023-00-01.prosody.json" "dialogue023/"
[...]
mv "DLG028-00-01.prosody.json" "dialogue028/"
[...]

If it is what you want, just pipe that output to bash and it will be executed:

for f in DLG*; do echo "$f" | sed 's/DLG\([0-9]\+\).*/mv "\0" "dialogue\1\/"/g'; done | bash
0

One line solution using find:

find . -name DLG* -exec bash -c 'DEST=$(echo "$0" | sed -r "s/DLG([0-9]+)-.*/dialogue\1/"); mkdir "$DEST"; mv "$0" "$DEST"' {} \;
  • find command look for DLG* files from this directory.
  • For every result execute the bash -c sentence.

In the bash sentence:

  • DEST=$(echo "$0" | sed -r "s/DLG([0-9]+)-.*/dialogue\1/"); picks every result from find ($0) and using sed replace the all numbers before the first - (DLG([0-9]+)-.*) with dialogue following with those numbers (dialogue\1) and put in on a variable called DEST.
  • mkdir "$DEST" creates the required folder.
  • mv "$0" "$DEST"' moves the file to that directory.
1
  • 1
    While this may answer the question, it would be a better answer if you could provide some explanation why it does so.
    – DavidPostill
    Commented May 29, 2015 at 17:48
0

A couple of ideas:

for i in DLG*-\*-\*-sprite.ogg; do echo "${i//[^0-9]}" | head -c 2; echo ;done

If you are sure they are all same length:

for i in DLG*-\*-\*-sprite.ogg; do echo "${i:3:3}" ;done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .