munsu
munsu

Reputation: 2062

Interweave contents of two directories into a new directory

I have two directories with sequential content (i.e., the contents' filenames are 001.jpg, 002.jpg, 003.jpg, and so on up to a maximum of 1000 files). I want to merge them into a new directory in alternating order like so:

Dir1
├── 001.jpg
├── 002.jpg
├── 003.jpg
└── 004.jpg
Dir2
├── 002.jpg
├── 003.jpg
├── 004.jpg
└── 005.jpg

OutputDir
├── 001.jpg (001.jpg from Dir1)
├── 002.jpg (002.jpg from Dir2)
├── 003.jpg (002.jpg from Dir1)
├── 004.jpg (003.jpg from Dir2)
├── 005.jpg (003.jpg from Dir1)
├── 006.jpg (004.jpg from Dir2)
├── 007.jpg (004.jpg from Dir1)
└── 008.jpg (005.jpg from Dir2)

This is what I have but it relies on both dirs having the same names:

cp Dir1/* OutputDir/
cp --backup=existing --suffix=.2 Dir2/* OutputDir/
cd OutputDir
# next line from here: https://stackoverflow.com/questions/3211595/renaming-files-in-a-folder-to-sequential-numbers
ls | cat -n | while read n f; do mv "$f" "$n.jpg"; done

I'm hoping for a solution that doesn't rely on the file names of both directories to be the same.

Upvotes: 0

Views: 46

Answers (2)

ghoti
ghoti

Reputation: 46856

Assuming the two input directories have the same number of files in each, you might be able to simply step through array indices, like this:

#!/usr/bin/env bash

a=(Dir1/*.jpg)
b=(Dir2/*.jpg)
n=1

for i in "${!a[@]}"; do
    mv "${a[$i]}" "OutputDir/$( printf '%03d' $n ).jpg"
    ((n++))
    mv "${b[$i]}" "OutputDir/$( printf '%03d' $n ).jpg"
    ((n++))
done

If there's the possibility they'll have different numbers of files, you'll need to define the behaviour for that and write something to handle it. Perhaps this:

#!/usr/bin/env bash

a=(Dir1/*.jpg)
b=(Dir2/*.jpg)

if [[ ${#a[@]} -gt ${#b[@]} ]]; then
        c=( ${!a[@]} )
else
        c=( ${!b[@]} )
fi

n=1

for i in "${c[@]}"; do
    echo "i=$i"
    [[ -f "${a[$i]}" ]] &&
      mv -v "${a[$i]}" "OutputDir/$( printf '%03d' $n ).jpg" && ((n++))
    [[ -f "${b[$i]}" ]] &&
      mv -v "${b[$i]}" "OutputDir/$( printf '%03d' $n ).jpg" && ((n++))
done

With this solution, if one directory has more files than the other, its files should be appended sequentially to OutputDir following the same counter. Note that ((n++)) only executes if a move is successful, which should insure that your output files are sequential without breaks.

The dependency here is that array indices must be sequential, without breaks.

Upvotes: 2

Gene
Gene

Reputation: 46960

Here's one way.

#! /bin/bash
a=(Dir1/*)
b=(Dir2/*)
for ((i=0;i<${#a[@]};++i)); do
  mv "${a[i]}" "OutputDir/$(printf '%03d.jpg' "$((2*i+1))")"
  mv "${b[i]}" "OutputDir/$(printf '%03d.jpg' "$((2*i+2))")"
done

It does assume the same number of files in Dir1 and Dir2, but your example implies that's true.

Upvotes: 2

Related Questions