List files in pairs using Bash [duplicate] - bash

This question already has answers here:
Looping over pairs of values in bash [duplicate]
(6 answers)
Closed 1 year ago.
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.

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.

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.

Related

How to rename a lot of files

I have directory of files called:
foo--ext1
foo--ext2
foo--ext3
...
I would like to rename them to:
foo-bar-ext1
foo-bar-ext2
foo-bar-ext3
....
How can I do this renaming in bash?
I have attempted to understand mywiki.wooledge.org/BashFAQ/030 but I can't work what should go in place of ${f%.foo}.bar"; in the first example.
So I have started with:
for f in foo--*; do echo mv -- "$f"
but what do I put next?
There are several ways to approach this.
I recommend bookmarking this page and referencing it often.
I would use this:
$: for f in foo--*; do mv "$f" "${f//foo--/foo-bar-}"; done
This uses string substitution in the current filename to construct the new name, replacing foo-- with foo-bar-.
Note the // in the replacement. This will replace every occurrence of foo-- with foo-bar- in each filename.
$: ls -l foo-*
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:32 foo-bar-ext1
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:32 foo-bar-ext2
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:32 foo-bar-ext3
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:33 foo-bar-foo-bar-etx4
Remove one of the leading slashes to make it only handle the first occurrence -
$: for f in foo--*; do mv "$f" "${f/foo--/foo-bar-}"; done
$: ls -l foo-*
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:34 foo-bar-ext1
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:34 foo-bar-ext2
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:34 foo-bar-ext3
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:34 foo-bar-foo--ext4
Another simple method avoiding the loop is to use rename (from the util-linux package). There all that is needed is:
rename "foo-" "foo-bar" foo--*
You can check what will be done before actually doing the rename with the -n (no-act) and -v (verbose) options. For your example files, that would be:
$ rename -nv "foo-" "foo-bar" foo--*
`foo--ext1' -> `foo-bar-ext1'
`foo--ext2' -> `foo-bar-ext2'
`foo--ext3' -> `foo-bar-ext3'
There are two versions of rename that you will find provided in Linux distributions, the rename above from the util-linux package and perl-rename, which some Linux distros use instead which will also install as rename. Both are capable of handling the rename, but the options will be different. Check which you have with rename --version before use.

Following symlinks with find to return the file the symlink is pointing to, not the symlink itself

I use usually use tmutil to control Timemachine instead of the GUI, which has some deficiencies to make it appealable to the masses. I tend to have a lot drives attached to my iMac, at this moment I have 11 with twenty total mounted partitions, but the drives and paritions change as I work on/with them. Sometimes many at a time.
I wrote a one-liner with the goal to report on the exclusion status of all drives in the /Volumes/ directory and an alias to it for simple reuse. alias tmutilvol="find /Volumes/ -maxdepth 1 -exec tmutil isexcluded {} \;" It works, well mostly. The typical output looks this is,
[Included] /Volumes
[Excluded] /Volumes/Backup-Lion
[Excluded] /Volumes/Backups
[Excluded] /Volumes/chris
[Excluded] /Volumes/El Capitan Temp Holding
[Excluded] /Volumes/Font
[Excluded] /Volumes/Hades
[Excluded] /Volumes/iMac Bad
[Excluded] /Volumes/iMac Clone
[Excluded] /Volumes/iMac Clone New
[Excluded] /Volumes/iMac ElCap
[Excluded] /Volumes/iMac HD
[Excluded] /Volumes/iMac HD New
[Excluded] /Volumes/iMac HS Clone
[Excluded] /Volumes/Macintosh HD Clone 1
[Excluded] /Volumes/maclaptop
[Excluded] /Volumes/Old Laptop
[Excluded] /Volumes/Old-Timemachine-Garnet
[Excluded] /Volumes/Old-Timemachine-Lion
[Excluded] /Volumes/TEMPORARY
[Excluded] /Volumes/Time Machine Mirror
The problem is /Volumes/iMac HD. This is not the actual drive, it is a symlink to it.
drwxr-xr-x 33 chris staff 1190 Jan 17 12:31 Backup-Lion
drwxrwxr-x 20 chris staff 748 Nov 11 22:03 Backups
drwxrwxr-x 107 chris staff 3706 Nov 13 16:26 El Capitan Temp Holding
drwxrwxr-x 82 chris staff 2856 Jan 19 16:07 Font
drwxr-xr-x 260 chris staff 8908 Jan 22 11:51 Hades
drwxr-xr-x# 41 chris staff 1462 Nov 11 22:03 Macintosh HD Clone 1
drwxr-xr-x 24 chris staff 884 Nov 11 22:03 Old Laptop
drwxr-xr-x 6 chris staff 272 Jan 17 12:31 Old-Timemachine-Garnet
drwxrwxr-x# 20 chris staff 748 Jan 19 14:49 Old-Timemachine-Lion
drwxr-xr-x 20 chris staff 748 Jan 22 11:54 TEMPORARY
drwxr-xr-x 12 chris staff 476 Jan 23 01:30 Time Machine Mirror
drwx------# 6 chris staff 272 Jan 16 16:18 chris
drwxrwxrwx 36 chris staff 1292 Jan 19 00:15 iMac Bad
drwxrwxrwx 29 chris staff 1054 Nov 13 16:26 iMac Clone
drwxr-xr-x 6 chris staff 272 Jan 17 16:05 iMac Clone New
drwxr-xr-x 30 chris staff 1088 Jan 16 17:31 iMac ElCap
lrwxr-xr-x 1 root wheel 1 Jan 16 20:34 iMac HD -> /
drwxr-xr-x 6 chris staff 272 Jan 17 16:05 iMac HD New
drwxrwxr-x 26 root wheel 952 Nov 13 16:26 iMac HS Clone
drwxrwxrwx 40 chris staff 1428 Jan 19 15:40 maclaptop
The result of tmutil isexcluded is actually for the symlink and not "/"
Kaze:~ chris$ tmutil isexcluded /
[Included] /
I want to know if there is a way to get find to follow and pass in the destination of the symlink. I read the find man page and about the -L option and thought that would do it and it does not. Some digging on stackexchange https://unix.stackexchange.com/questions/31114/find-usage-with-l explained why it doesn't work. What I have not been able to find is any clue as to how I might do what want and keep a simple one-liner or if I am going to have to write a function for this and deal with symlinks in some convoluted way.
I am hoping that someone with a lot more knowledge of CLI and bash than I might know how to do what I want simply.
Have you tried?
readlink "/Volumes/iMac HD"
one liner for mac:
find /Volumes -maxdepth 1 -exec bash -c 'N="{}"; L=`readlink "{}"`; tmutil isexcluded "${L:-$N}"' \;
Explanation:
have to use two variables, $L for readlink output, $N for original name.
${L:-$N} basically just output $L if its not empty, else output $N
Note that I have to prefix $L with "/Volumes/" as MacOS's readlink does not output the absolute path. Linux "readlink -f" solves this issue.

Successfully delete stringutil.a but it comes back on its own

I'm following "How to Write Go Code" and tries to delete stringutil.a under $GOPATH/pkg/darwin_amd64/github.com/user. The delete is successful but the file comes back on its own. I'm confused. What is happening?
zps-MacBook-Air:haibin haibin$ rm stringutil.a
zps-MacBook-Air:haibin haibin$ ls -lah
total 0
drwxr-xr-x 2 haibin staff 68B Feb 15 00:57 .
drwxr-xr-x 17 haibin staff 578B Feb 15 00:39 ..
zps-MacBook-Air:haibin haibin$ ls -lah
total 8
drwxr-xr-x 3 haibin staff 102B Feb 15 00:57 .
drwxr-xr-x 17 haibin staff 578B Feb 15 00:39 ..
-rw-r--r-- 1 haibin wheel 2.4K Feb 15 00:57 stringutil.a
You need to delete the stringutil.go source file that is under the src tree. The *.a file is a binary file which results from the compilation (and possibly linking) of source files.

How Can I Create Multiple Files of Random Data?

I've been using dd if=/dev/random of=<file_name> bs=XX count=XX to create single files of random data. But I wondered how I could create multiple files at once. Say 5, 10, or 80,000. I need to do some bandwidth testing and need unique data. The above code works great for 1 or 2 files. My programming (Python) and terminal skill are still very minimal.
Any help would be awesome.
man split.
Split splits a file or stdin to multiple files based on file size or number of lines. It doesn't happen "at once" or in parallel though.
dd if=/dev/random bs=1 count=10 | split -b 2 produces 5 files xaa,xab..xae each consisting of 2 bytes.
I would use GNU Parallel for this. The command line syntax is very intuitive and concise and it does all your work in parallel, i.e. FAST, and uses all those lovely CPU cores in your Mac.
So, to create 8 files in parallel, each of 100MB, you would type this in the Terminal:
$ parallel dd if=/dev/random of=random-{} bs=1000000 count=100 ::: {0..7}
and you will end up with these 8 files just 60 seconds later:
$ ls -l random-*
-rw-r--r--# 1 mark staff 100000000 19 Dec 11:52 random-0
-rw-r--r--# 1 mark staff 100000000 19 Dec 11:52 random-1
-rw-r--r--# 1 mark staff 100000000 19 Dec 11:52 random-2
-rw-r--r--# 1 mark staff 100000000 19 Dec 11:52 random-3
-rw-r--r--# 1 mark staff 100000000 19 Dec 11:52 random-4
-rw-r--r--# 1 mark staff 100000000 19 Dec 11:52 random-5
-rw-r--r--# 1 mark staff 100000000 19 Dec 11:52 random-6
-rw-r--r--# 1 mark staff 100000000 19 Dec 11:52 random-7
Or, if you wanted one file of 1kB, two files of 64kB, one file of 32kB and one of 128kB, you would do this:
$ parallel dd if=/dev/random of=random-{%} bs=1024 count={1} ::: 1 64 64 32 128
which will give you this:
-rw-r--r-- 1 mark staff 131072 19 Dec 12:10 random-5
-rw-r--r-- 1 mark staff 32768 19 Dec 12:10 random-4
-rw-r--r-- 1 mark staff 65536 19 Dec 12:10 random-3
-rw-r--r-- 1 mark staff 65536 19 Dec 12:10 random-2
-rw-r--r-- 1 mark staff 1024 19 Dec 12:10 random-1
The easiest way, to my mind, of installing parallel on OSX is to get homebrew from the homebrew website, then all you do is:
brew install parallel

FFMPEG fails to find any files matching the regexp

I want to convert sequence of 40 images to a video. The problem is that ffmpeg could not find any of the inputs images matching the regexp in the command. What am I doing wrong please?
I ran the following commands:
> ffmpeg -f image2 -i "img%0d.jpg" -vcodec mpeg4 -y -v "verbose" 07_seq_wire.avi
*** THIS PROGRAM IS DEPRECATED ***
This program is only provided for compatibility and will be removed in a future release. Please use avconv instead.
img%0d.jpg: No such file or directory
> ls -l
-rw-r--r-- 1 david david 69812 Apr 11 01:54 img01.jpg
-rw-r--r-- 1 david david 70858 Apr 11 01:54 img02.jpg
-rw-r--r-- 1 david david 71481 Apr 11 01:54 img03.jpg
-rw-r--r-- 1 david david 71528 Apr 11 01:54 img04.jpg
-rw-r--r-- 1 david david 71470 Apr 11 01:54 img05.jpg
-rw-r--r-- 1 david david 71534 Apr 11 01:54 img06.jpg
-rw-r--r-- 1 david david 70908 Apr 11 01:54 img07.jpg
-rw-r--r-- 1 david david 70633 Apr 11 01:54 img08.jpg
-rw-r--r-- 1 david david 70059 Apr 11 01:54 img09.jpg
-rw-r--r-- 1 david david 70021 Apr 11 01:54 img10.jpg
-rw-r--r-- 1 david david 69726 Apr 11 01:54 img11.jpg
-rw-r--r-- 1 david david 70896 Apr 11 01:54 img12.jpg
-rw-r--r-- 1 david david 72123 Apr 11 01:54 img13.jpg
-rw-r--r-- 1 david david 72605 Apr 11 01:54 img14.jpg
-rw-r--r-- 1 david david 73501 Apr 11 01:54 img15.jpg
-rw-r--r-- 1 david david 73743 Apr 11 01:54 img16.jpg
-rw-r--r-- 1 david david 74401 Apr 11 01:54 img17.jpg
-rw-r--r-- 1 david david 74697 Apr 11 01:54 img18.jpg
-rw-r--r-- 1 david david 75371 Apr 11 01:54 img19.jpg
-rw-r--r-- 1 david david 74802 Apr 11 01:54 img20.jpg
-rw-r--r-- 1 david david 74802 Apr 11 01:55 img21.jpg
-rw-r--r-- 1 david david 75371 Apr 11 01:55 img22.jpg
-rw-r--r-- 1 david david 74697 Apr 11 01:55 img23.jpg
-rw-r--r-- 1 david david 74401 Apr 11 01:55 img24.jpg
-rw-r--r-- 1 david david 73743 Apr 11 01:55 img25.jpg
-rw-r--r-- 1 david david 73501 Apr 11 01:55 img26.jpg
-rw-r--r-- 1 david david 72605 Apr 11 01:55 img27.jpg
-rw-r--r-- 1 david david 72123 Apr 11 01:55 img28.jpg
-rw-r--r-- 1 david david 70896 Apr 11 01:55 img29.jpg
-rw-r--r-- 1 david david 69726 Apr 11 01:55 img30.jpg
-rw-r--r-- 1 david david 70021 Apr 11 01:55 img31.jpg
-rw-r--r-- 1 david david 70059 Apr 11 01:55 img32.jpg
-rw-r--r-- 1 david david 70633 Apr 11 01:55 img33.jpg
-rw-r--r-- 1 david david 70908 Apr 11 01:55 img34.jpg
-rw-r--r-- 1 david david 71534 Apr 11 01:55 img35.jpg
-rw-r--r-- 1 david david 71470 Apr 11 01:55 img36.jpg
-rw-r--r-- 1 david david 71528 Apr 11 01:55 img37.jpg
-rw-r--r-- 1 david david 71481 Apr 11 01:55 img38.jpg
-rw-r--r-- 1 david david 70858 Apr 11 01:56 img39.jpg
-rw-r--r-- 1 david david 69812 Apr 11 01:56 img40.jpg
Thanks for any help!
Try changing img%0d.jpg to img%2d.jpg.
It worked for me when I did this.
You will have to set a bit rate with -b:v 1024K, or a quality level with -q:v 2 (range from 1 to 31, 2–5 being sane choices) to change the quality of the output. Without specifying anything, the default bit rate will be very low and result in bad visual quality.

Resources