0

I have a collection of files in a directory. They are left and right audio tracks for each filename. I want them to be listed by bash as filename_l filename_r so I can use sox to merge each one together. But I am not having any luck with a bash loop.

I need the files listed in the loop as 1-2 3-4 5-6 7-8 9-10 11-12 et cetera. But I am not sure how to go about this.

-rwxrwxrwx  1 jason jason  653K Oct 25 14:24 05_wasteland2_str_l.ogg
-rwxrwxrwx  1 jason jason  648K Oct 25 14:24 05_wasteland2_str_r.ogg
-rwxrwxrwx  1 jason jason  1.5M Oct 25 14:24 amb0010_l.ogg
-rwxrwxrwx  1 jason jason  1.5M Oct 25 14:24 amb0010_r.ogg
-rwxrwxrwx  1 jason jason  1.4M Oct 25 14:24 amb0016_l.ogg
-rwxrwxrwx  1 jason jason  1.4M Oct 25 14:24 amb0016_r.ogg
-rwxrwxrwx  1 jason jason  2.9M Oct 25 14:24 amb0017_l.ogg
-rwxrwxrwx  1 jason jason  2.9M Oct 25 14:24 amb0017_r.ogg
-rwxrwxrwx  1 jason jason  2.6M Oct 25 14:24 amb0019_l.ogg
-rwxrwxrwx  1 jason jason  2.6M Oct 25 14:24 amb0019_r.ogg
-rwxrwxrwx  1 jason jason  1.8M Oct 25 14:24 amb001_l.ogg
-rwxrwxrwx  1 jason jason  1.8M Oct 25 14:24 amb001_r.ogg
-rwxrwxrwx  1 jason jason  2.0M Oct 25 14:24 amb006_l.ogg
-rwxrwxrwx  1 jason jason  2.0M Oct 25 14:24 amb006_r.ogg
-rwxrwxrwx  1 jason jason  1.9M Oct 25 14:24 amb007_l.ogg
-rwxrwxrwx  1 jason jason  1.9M Oct 25 14:24 amb007_r.ogg
-rwxrwxrwx  1 jason jason  4.5M Oct 25 14:24 amb01_l.ogg
-rwxrwxrwx  1 jason jason  4.5M Oct 25 14:24 amb01_r.ogg
-rwxrwxrwx  1 jason jason  3.0M Oct 25 14:24 amb02_l.ogg
-rwxrwxrwx  1 jason jason  3.0M Oct 25 14:24 amb02_r.ogg
-rwxrwxrwx  1 jason jason  2.5M Oct 25 14:24 amb03_l.ogg
-rwxrwxrwx  1 jason jason  2.5M Oct 25 14:24 amb03_r.ogg
-rwxrwxrwx  1 jason jason  2.2M Oct 25 14:24 amb04_l.ogg
-rwxrwxrwx  1 jason jason  2.2M Oct 25 14:24 amb04_r.ogg
-rwxrwxrwx  1 jason jason  2.3M Oct 25 14:24 amb05_l.ogg
-rwxrwxrwx  1 jason jason  2.3M Oct 25 14:24 amb05_r.ogg

I tried this bash loop, but it does not do what I need, but there must be something small I am missing.

declare -a files=(*.ogg)
for (( i = 0; i < ${#files[*]}; ++ i ))
do
  echo ${files[$i]} ${files[$i+1]}

done

There are 486 files in total, and doing this by hand will take too logn and be prone to mistakes. Every loop I have tried has gone 1-2 2-3 3-4 4-5 et cetera, I need this do work differently, so each file is listed with it`s partner. The existing loop I have gives this output.

05_wasteland2_str_l.ogg 05_wasteland2_str_r.ogg
05_wasteland2_str_r.ogg amb0010_l.ogg
amb0010_l.ogg amb0010_r.ogg
amb0010_r.ogg amb0016_l.ogg
amb0016_l.ogg amb0016_r.ogg
amb0016_r.ogg amb0017_l.ogg
amb0017_l.ogg amb0017_r.ogg
amb0017_r.ogg amb0019_l.ogg
amb0019_l.ogg amb0019_r.ogg
amb0019_r.ogg amb001_l.ogg
amb001_l.ogg amb001_r.ogg
amb001_r.ogg amb006_l.ogg
amb006_l.ogg amb006_r.ogg
amb006_r.ogg amb007_l.ogg
amb007_l.ogg amb007_r.ogg
amb007_r.ogg amb01_l.ogg
amb01_l.ogg amb01_r.ogg
amb01_r.ogg amb02_l.ogg
amb02_l.ogg amb02_r.ogg

This is not what I am after. But I hope there is a simple solution to this problem.

I want to be able to output this.

05_wasteland2_str_l.ogg 05_wasteland2_str_r.ogg

For each of the files, _l and _r. I want to be able to use sox to merge each pair of files.

That way I can use this to merge the files.

sox -M 05_wasteland2_str_l.ogg 05_wasteland2_str_r.ogg 05_wasteland2_merged.ogg

But listing the files in pairs is what I am finding very difficult. This could end up being quite challenging.

  • Please edit your Q to show your required output from your sample input. (We only need 4-6 lines of sample input, unless there are special cases). Good luck. – shellter Oct 26 '20 at 01:02
  • These code blocks are not runnable in the browser, so they should not be fancy “code snippets”. Please just use basic code blocks – use ``` above and below each block or indent each block by at least four spaces. – Brian Drake Oct 26 '20 at 01:19

2 Answers2

1

You could use the fact that there are pairs of otherwise identically named files with _l and _r:

for f in *_l.ogg; do
    echo "$f" "${f/%_l.ogg/_r.ogg}"
done

This loops over all files ending in _l.ogg, and then prints pairs of these files together with the file where _l.ogg (anchored at the end of the string) is replaced by _r.ogg.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
  • I used this script to merge all files using your answer. for f in *_l.ogg; do sox -M "$f" "${f/_l/_r}" ../musicfiles\/$f.ogg done This merged all files and this worked just fine. A couple of files had _r and _l in their filenames and they were skipped, but this is something I can fix manually. Thank you. – John Cartwright Oct 26 '20 at 01:48
  • 1
    Using `"${f/%_l.ogg/_r.ogg}"` instead of "${f/_l/_r}" would work on files that had other occurrences of "_l" in the filename. – Gordon Davisson Oct 26 '20 at 04:03
0

You are currently iterating over files, but you want to iterate over pairs of files. There are half as many pairs of files as there are files (${#files[*]}/2).

The indexes need to become $i*2 and $i*2+1.

Complete code, with these changes included:

declare -a files=(*.ogg)
for (( i = 0; i < ${#files[*]}/2; ++ i ))
do
  echo ${files[$i*2]} ${files[$i*2+1]}

done

This answer requires minimal changes to your existing code. However, it assumes that the files array is sorted and consists entirely of pairs of files in the expected format. Benjamin W.’s answer does not make these assumptions.

Brian Drake
  • 346
  • 1
  • 8