My goal is to reduce the size of all .ogg files found under the parent directory "Formatted", while keeping the sub-directories and files structure the same.
Example
.../Formatted/"test1, test2, test3 and so on"/"files.ogg"
to
.../Contributors/"test1, test2, test3 and so on"/"reduced_files.ogg"
However. While the script runs ffmpeg it seems that the some input file paths gives "Error opening input: No such file or directory". eg. It either cuts off the 'h' of home or adds a '.' to the end of the file extension.
"ome/user1/Downloads/Encoding/Formatted/test1/"file""
or
Parse error, at least 3 arguments were expected, only 1 given in string "oding/Formatted/test1/"file"
Resulting in
.../Contributors/"test1, test2, test3 and so on"/ with only a single file or missing .ogg files.
I'm new to coding, any help is appreciated .
I've tried echoing the variables to make sure they are correct but early on in the process echo "3" "$dirName"
shows the absolute path being inrorrect.
#!/bin/bash
sourceDir=$HOME/Downloads/Encoding/Formatted
destDir=$HOME/Backup/LEARN/Contributors
find ~/Downloads/Encoding/Formatted/ -type f -name "*.ogg" | while IFS= read -r d; do
# find -name "*.ogg"
echo "1" "$d"
baseName=$(basename "$d")
echo "2" "$baseName"
dirName=$(dirname "$d")
echo "3" "$dirName"
dirName_0=$(basename "$dirName")
echo "4" "$dirName_0"
echo "5" "$destDir"
outputDir="$destDir/$dirName_0"
echo "6" "$outputDir"
outputPath="$outputDir/$baseName"
# echo "1" "$d"
# echo "2" "$baseName"
echo "3" "$dirName"
# echo "4" "$dirName_0"
# echo "5" "$destDirecho"
# echo "6" "$outputDir"
# echo "7" "$outputPath"
# echo "8" "$destDir/$dirName_0/$baseName"
# echo "9" "$sourceDir"
mkdir -p "$outputDir"
ffmpeg -i "$d" -b:a 24k -acodec libopus -map_metadata 0 -map_metadata 0:s:0 "$outputPath"
done
For the first file found, *echo* returns:
1 /home/user/Downloads/Encoding/Formatted/test/file1.ogg
2 file1.ogg
3 /home/user/Downloads/Encoding/Formatted/test
4 test
5 /home/user/Backup/LEARN/Contributors
6 /home/user/Backup/LEARN/Contributors/test
7 /home/user/Backup/LEARN/Contributors/test/file1.ogg
8 /home/user/Backup/LEARN/Contributors/test/file1.ogg
9 /home/user/Downloads/Encoding/Formatted
Which is correct, but then for the next file found:
1 ome/user/Downloads/Encoding/Formatted/test/file2.ogg
2 file2.ogg
3 ome/user/Downloads/Encoding/Formatted/test
4 test
5 /home/user/Backup/LEARN/Contributors
6 /home/user/Backup/LEARN/Contributors/test
7 /home/user/Backup/LEARN/Contributors/test/file2.ogg
8 /home/user/Backup/LEARN/Contributors/test/file2.ogg
9 /home/user/Downloads/Encoding/Formatted
line 1 and 3 both miss a h from home? It does this for files in multiple folders.
FFmpeg has an interaction mode enabled by default. With that, you can type for e.g. ?
to get help in the console. And it reads that from the input, which in your case is the result of the find
command. So, it reads the first char of your path as input and removes it.
To prevent this, use the -nostdin
flag, which disables interaction.
And now to preserve your subdirectory structure, first cd
into the source directory then run the find
command. This way, you will get the paths relative to the source directory, which you can concat with your destination directory. Your current solution only works for files located within a single subdir of the source directory.
Here is the code:
#!/bin/bash
sourceDir=$HOME/Downloads/Encoding/Formatted
destDir=$HOME/Backup/LEARN/Contributors
cd "$sourceDir"
find . -type f -name "*.ogg" | while IFS= read -r relPath; do
inputFile="$sourceDir/$relPath"
outputFile="$destDir/$rel_path"
mkdir -p "$(dirname "$outputFile")"
ffmpeg -nostdin -i "$inputFile" -b:a 24k -acodec libopus -map_metadata 0 -map_metadata 0:s:0 "$outputFile"
done