[SOLVED] BASH - script to loop through files in size order descending
Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
BASH - script to loop through files in size order descending
I can write a simple for loop to loop through files in name order.
Code:
for ff in *.mp4; do HandBrakeCLI -i "$ff" -o "X$ff";done
This works fine with a command in the do section to process the $ff file
But I want the list in size order descending so I did this
Code:
for ff in "$( ls *.mp4 | sort -r )"; do echo "$ff"; done
which results in this
Code:
$ for ff in "$( ls *.mp4 | sort -r )"; do echo "$ff"; done;
X BIG.mp4
CMID.mp4
BMID.mp4
ASMALL.mp4
Fine I thought, sorted in size order escending, just need to put my command in the do section
Code:
for ff in "$( ls *.mp4 | sort -r )"; do HandBrakeCLI -i "$ff" -o "X$ff"; done
But I was wrong, there is a /n hidden in $ff whcih lets it display but not much use sending the whole list of files to HandBrakeCLI in one hit.
The result
Code:
$ for ff in "$( ls *.mp4 | sort -r )"; do HandBrakeCLI -i "$ff" -o "X$ff"; done;
[16:03:52] hb_init: starting libhb thread
[16:03:52] thread 7fbf823a0700 started ("libhb")
HandBrake 1.3.1 (2020032300) - Linux x86_64 - https://handbrake.fr
16 CPUs detected
Opening X BIG.mp4
CMID.mp4
BMID.mp4
ASMALL.mp4...
[16:03:52] CPU: Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
[16:03:52] - logical processor count: 16
[16:03:52] hb_scan: path=X BIG.mp4
CMID.mp4
BMID.mp4
ASMALL.mp4, title_index=1
disc.c:323: failed opening UDF image X BIG.mp4
CMID.mp4
BMID.mp4
ASMALL.mp4
disc.c:424: error opening file BDMV/index.bdmv
disc.c:424: error opening file BDMV/BACKUP/index.bdmv
....
..
......
How do I seperate the list into individual movies to be processed squentially?
This does not work because $( ) becomes a string that is protected by the quotes.
Without the quotes the string is subject to word splitting (partly desired) and filename generation (not desired).
The best solution is a while-read loop
Code:
ls *.mp4 | sort -r | while IFS= read -r ff; do
Each read reads one line. IFS="" and -r turn
off some magic in read.
Commands in the loop body that can read from stdin would compete with the read, and should be redirected </dev/null
If HandBrakeCLI is such a command:
Code:
</dev/null HandBrakeCLI ...
Regarding
ls *.mp4 | sort -r
This is not by size but reverse alphabetical, like
ls -r *.mp4
Last edited by MadeInGermany; 04-16-2023 at 11:54 AM.
This does not work because $( ) becomes a string that is protected by the quotes.
Without the quotes the string is subject to word splitting (partly desired) and filename generation (not desired).
The best solution is a while-read loop
Code:
ls *.mp4 | sort -r | while IFS= read -r ff; do
Each read reads one line. IFS="" and -r turn
off some magic in read.
Commands in the loop body that can read from stdin would compete with the read, and should be redirected </dev/null
If HandBrakeCLI is such a command:
Code:
</dev/null HandBrakeCLI ...
Regarding
ls *.mp4 | sort -r
This is not by size but reverse alphabetical, like
ls -r *.mp4
You're absolutely correct about it NOT sorted by size, my mistake. Thanks for pointing that out.
Anyway I trid it like this
Code:
ls *.mp4 | sort -r | while IFS= read -r ff; do HandBrakeCLI -i "$ff" -o "X$ff" --stop-at seconds:20 ; done
but yet again it stopped after processing the first file!
find *.mp4 -type f -exec du -h {} + | sort -rh
find *.mp4 -type f -exec ls -lS {} +
Code:
files1=(*.mp4)
files2=($(du -a <<< "$files1" | sort -nr))
printf '%s\n' "${files2[@]}"
for i in "${files1[@]}"; do
echo "$i"
sleep 1
done
for i in "${files2[@]}"; do
echo ${i##*/}
sleep 1
done
#First will fail, the rest will be ok
for i in "${files2[@]}"; do
echo "HandBrakeCLI -i ${i##*/} -o New_${i##*/}"
sleep 1
done
If ls can sort it, do not re-sort it by piping to sort!
Perhaps you want to reverse the order, then you must tell the ls to do it:
Code:
ls *.mp4 -rS | while ...
Regarding the </dev/null, I tried to explain it.
The loop's stdin is fed by the pipe.
Not only the read can read a line from the stdin.
Obviously the HandBrakeCLI reads from the stdin, too. And "steals" it, so the read doesn't get it.
If ls can sort it, do not re-sort it by piping to sort!
Perhaps you want to reverse the order, then you must tell the ls to do it:
Code:
ls *.mp4 -rS | while ...
Regarding the </dev/null, I tried to explain it.
The loop's stdin is fed by the pipe.
Not only the read can read a line from the stdin.
Obviously the HandBrakeCLI reads from the stdin, too. And "steals" it, so the read doesn't get it.
Sorry, I did read your original post, but it didn't register in my 72yr old brain!!
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.