4

I have a main directory with 100 .mp4 files. I also have a set of sub-directories that goes dir_1, dir_2, dir_3, etc, up to 100. What I want do is to loop through the main directory and distribute the .mp4 files to all the subfolders, each having only one. Then, there should be two loops or one loop with two variables, whichever one is possible. This is approximately what I'm trying to achieve in a single line of code.

for file in *.mp4 & x in {1..100}; do mv $file dir_$x; done

3 Answers3

11
set -- *.mp4

for dir in dir_*/; do
    mv -- "$1" "$dir"
    shift
done

This first assigns the names of all the MP4 files to the list of positional parameters using set. It then iterates over the directories matching the pattern dir_*/. For each directory, it moves the first MP4 file from the list of positional parameters into that directory, and then shifts that MP4 file off the list.

There is no check to verify that there are as many directories as MP4 files in the above code. Would you want that, you could do

set -- *.mp4

for dir in dir_*/; do
    if [ "$#" -eq 0 ]; then
        echo 'Ran out of MP4 files' >&2
        exit 1
    fi
    mv -- "$1" "$dir"
done

if [ "$#" -ne 0 ]; then
    echo 'Too many MP4 files' >&2
    exit 1
fi

This code would work in any sh-like POSIX shell.

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
5

Use one loop, increment the counter using an arithmetic expression.

x=1
for file in *.mp4 ; do
    mv -- "$file" dir_$x/
    ((++x))
done

Double quote the file name, as mp4s can contain whitespace in their names. Use -- in front of "$file" to avoid interpreting the filename as a set of options if it starts with a dash.

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
choroba
  • 45,735
  • 7
  • 84
  • 110
  • 1
    And without bashisms, the fourth line is `x=$((x+1))`. – Quasímodo Dec 10 '21 at 20:55
  • @Quasímodo Without bashisms, the fourth line is `x=\`expr $x + 1\`` – David G. Dec 11 '21 at 14:41
  • @DavidG., see https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/V3_chap02.html#tag_18_06_04 and [Have backticks (i.e. `cmd`) in *sh shells been deprecated?](https://unix.stackexchange.com/questions/126927/have-backticks-i-e-cmd-in-sh-shells-been-deprecated) – ilkkachu Dec 12 '21 at 00:12
  • 1
    You don't need an external call to `expr` for arithmetic. `x=$((x + 1))` (as well as, I think, `: $((x++))`) is POSIX-compliant. – chepner Dec 12 '21 at 19:04
2

An other bashism:

#!/bin/bash

mp4=( ./*.mp4 )
for i in "${!mp4[@]}"
do
    mv "${mp4[i]}" "dir_$i/"
done

I wouldn't use it in your case but it's always interesting to see different methods.

Fravadona
  • 541
  • 2
  • 11