How to reverse a for loop in a bash script [duplicate] - linux

This question already has answers here:
How to loop over files in natural order in Bash?
(7 answers)
Closed 5 years ago.
I need to reverse a for loop in a bash script. There is a directory with videos named after %Y%m.mp4 (201701.mp4; 201702.mp4, 201703.mp4, ...). The loop should start with the oldest filename (e.g. 201712.mp4) How to reverse my for loop?
outputdir="/path/to/video/monthly/"
for file in "$outputdir"*.mp4
do
echo $file
done

You can list your files in a reserved order in the following way:
ls -1 $outputdir/*.mp4 | sort -r
So in you script you can do:
outputdir="/path/to/video/monthly/"
for file in $(ls -1 $outputdir*.mp4 | sort -r)
do
echo $file
done
NOTE: As #PesaThe pointed out this solution would fail to work with filenames with spaces. If it is the case for you, you should quote the command: "$(ls -1 $outputdir*.mp4 | sort -r)" and use "$file"
UPDATE:
See the following test
mkdir test && cd $_
for i in {1..5}; do touch test_$i.txt; done
cd -
And ls -1 test/*.txt will output:
test/test_1.txt
test/test_2.txt
test/test_3.txt
test/test_4.txt
test/test_5.txt
And ls -1 test/*txt | sort -r will output:
test/test_5.txt
test/test_4.txt
test/test_3.txt
test/test_2.txt
test/test_1.txt

Related

Piping into a part of bash command stored in variable [duplicate]

This question already has answers here:
Conditional step in a pipeline
(2 answers)
Can I make a shell function in as a pipeline conditionally "disappear", without using cat?
(1 answer)
Closed 4 months ago.
EMPTY_VAR=''
MMDDYYYY='6.18.1997'
PIPE_VAR=' | xargs echo "1+" | bc'
echo "$MMDDYYYY" | cut -d "." -f 2${EMPTY_VAR}
>> 18
Command above would give me correct output, which is 18, but if I try to use PIPE_VAR instead it would give me bunch of errors:
echo "$MMDDYYYY" | cut -d "." -f 2${PIPE_VAR}
cut: '|': No such file or directory
cut: xargs: No such file or directory
cut: echo: No such file or directory
cut: '"1+"': No such file or directory
cut: '|': No such file or directory
cut: bc: No such file or directory
OR:
echo "$MMDDYYYY" | cut -d "." -f 2"$PIPE_VAR"
cut: invalid field value ‘| xargs echo "1+" | bc’
Try 'cut --help' for more information.
What I'm really trying to find out is that even possible to combine commands like this?
You can't put control operators like | in a variable, at least not without resorting to something like eval. Syntax parsing comes before parameter expansion when evaluating the command line, so Bash is only ever going to see that | as a literal character and not pipeline syntax. See BashParsing for more details.
Conditionally adding a pipeline is hard to do well, but having a part of the pipeline conditionally execute one command or another is more straightforward. It might look something like this:
#!/bin/bash
MMDDYYYY='6.18.1997'
echo "$MMDDYYYY" | cut -d "." -f 2 |
if some_conditional_command ; then
xargs echo "1+" | bc
else
cat
fi
It looks like you're trying to calculate the next day. That's hard to do with plain arithmetic, particularly with month/year ends.
Let date do the work. This is GNU date. It can't parse 6.18.1997 but it can parse 6/18/1997
for MMDDYYYY in '2.28.1996' '2.28.1997'; do
date_with_slashes=${MMDDYYYY//./\/}
next_day=$(date -d "$date_with_slashes + 1 day" '+%-m.%-d.%Y')
echo "$next_day"
done
2.29.1996
3.1.1997

Execute script for all but certain files in directory [duplicate]

This question already has answers here:
How do I exclude a directory when using `find`?
(46 answers)
Closed 3 years ago.
I need a bash script to iterate on all files in directory besides one with specific names. Maybe it can be done with help of awk/sed during script execution?
Here is my script, that simply merge all file in directory to one:
#!/bin/bash
(find $DIR_NAME -name app.gz\* | sort -rV | xargs -L1 gunzip -c 2> /dev/null || :)
How can I add some $DIR_NAME to list, and don`t iterate over them?
Put the names of the files to be excluded into a file, say "blacklist.txt", one filename per line. Then use
... | grep -F -f blacklist.txt | sort ...
to exclude them from the input to xargs.

Change file names iteratively in Linux [duplicate]

This question already has answers here:
Rename multiple files in bash
(3 answers)
Closed 8 years ago.
The only way I am aware of to do this operation is with a for loop iterating over each file:
for file in *something.txt; do
out=\`echo $file | sed 's/something/else/'\`; mv $file $out;
done
I was wondering if there is any other way or shortcut for it (using GNU bash).
There is also simple substring replacement provided as part of bash itself:
mv $file ${file/something/else}
example:
$ touch {1..3}something.txt
$ ( for i in *something.txt; do mv $i ${i/something/else}; done )
$ ls -1 *else*
1else.txt
2else.txt
3else.txt
There's rename and the same basic loop concept as in your post only in whatever programming language you choose.

How to set bash next bash operation input equal to the output of the prvious operation? [duplicate]

This question already has answers here:
Use the output of a command as input of the next command
(4 answers)
How to apply shell command to each line of a command output?
(9 answers)
Closed 8 years ago.
I believe it is really easy, but I didn't find anywhere an answer for me. What I'm trying to do is:
echo file.war | sed s/.war// | rm -rf ???
to pass to the rm -rf the output of the sed command.
Not sure if it is the right way to get this...
Thanks for your help in advance!
This is what 'xargs' does.
echo file.war | sed s/\.war$// | xargs rm -rf
And note my changes to your regex. It needs to be anchored and the '.' needs to be escaped.
Other possibilities, in bash:
Use command substitution:
rm -rf $(echo file.war | sed 's/\.war$//')
Use a variable and shell parameter expansion:
file=file.war
rm -rf "${file%.war}"
Instead of the echo | sed, use a here-string (and the command substitution):
rm -rf $(sed 's/\.war$//' <<< "file.war")
This was in fact just to show you the command substitution $(...) thing (avoiding xargs that will fail miserably if you have file names containing funny symbols like spaces). Also to show you that in your case, sed is useless (thanks to the shell parameter expansion) and, if you really need sed, that the echo | sed thing can be avoided in bash.
I don't know what exactly you're trying to achieve. I could imagine:
you're trying to delete all files file such that file.war exist in current directory. In this case, I would do:
for file in *.war; do
rm -rf -- "${file%.war}"
done
You have a file called filenames that contains lines like:
file1.war
file2.war
...
filen.war
and you want to delete all files file1, file2, …, filen. Then I would do:
while read -r file; do
[[ ( $file = *.war ) && ( -f $file ) ]] || continue
rm -rf -- "${file%.war}"
done < filenames
An alternative approach is
rm -rf `echo file.war | sed s/\.war$//`

how to delete filename's specific suffix in a dir, in linux [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Extract filename and extension in bash
Linux: remove file extensions for multiple files
For example, A.txt B.txt, I want to rename then to A and B .
How can I do it with shell script? Or other method ? Thanks.
for i in *.txt; do mv "$i" "${i%.txt}"; done
I would use something like:
#!/bin/bash
for file in *.txt
do
echo "$file" "$( echo $file | sed -e 's/\.txt//' )"
done
Of course replace the two above references of ".txt" to whatever file extension you are removing, or, preferably just use $1 (the first passed argument to the script).
Michael G.
for FILE in *.txt ; do mv -i "$FILE" "$(basename "$FILE" .txt)" ; done

Resources