Bash script to change file extension using regex - regex

I have a lot of files i've copied over from my iphone file system, to start with they were mp3 files, but app on iphone changed their names to some random staff which looks like:
1c03e04cc1bbfcb0c1237f57f1d0ae2e.mp3?extra=f7NhT68pNkmEbGA_I1WbVShXQ2E2gJAGBKSEyh3hf0hsbLB1cqnXDuepYA5ubcFm_B3KSsrXDuKVtWVAUh_MAPeFiEHXVdg
I only need to remove part of file name after mp3. Please give me a script - there are more than 600 files, and manually it is impossible.

you can use rename command:
rename "s/mp3\?.*/mp3/" *.mp3*

#!/bin/bash
shopt -s nullglob
for F in *.mp3\?*; do
echo mv -v -- "$F" "${F%%.mp3\?*}.mp3"
done
Save it to a script like script.sh then run as bash /path/to/script.sh in the directory where the files exist.
Remove echo when you find it correct already.

Related

Use sed/regex to rename a file - bash with macOS

I have a list of files that a date has been added to the end.
ex: Chorus Left Octave (consolidated) (2020_10_14 20_27_18 UTC). The files will end with .wav or .mp3
I want to leave the (consolidated) but take out the date. I have come up with the regex and tested with regexr.com. It does format the text correctly there.
The regex is: /(\([0-9]+(.*)(?=.wav|.mp3))+/g
Now, I am trying to actually rename the files. In my terminal I have cd'ed into the folder with the files. Based on other answers here I have tried:
rename -n '/(\([0-9]+(.*)(?=.wav|.mp3))+/g' *.wav|*.mp3 - using rename installed with homebrew
sed '/(\([0-9]+(.*))+/g' *.wav|*.mp3
for f in *.wav|*.mp3; do mv "$f" "${f/(\([0-9]+(.*)(?=.wav|.mp3))+/g}” done
The first two do not throw any errors, but do not do any renames (I know that the -n after rename just prints out the files that will be changed, it doesn't actually change the files)
The last one starts a bash session.
I'd rather use the rename or sed, seems simpler to me. But, what am I doing wrong?.
In plain bash:
#!/bin/bash
pat='([0-9][0-9][0-9][0-9]_[0-9][0-9]_[0-9][0-9] [0-9][0-9]_[0-9][0-9]_[0-9][0-9] UTC)'
for f in *.mp3 *.wav; do echo mv "$f" "${f/$pat}"; done
Remove the echo preceding the mv after making sure it will work as intended. You may also consider adding the -i option to the mv in order to avoid clobbering an existing file unintentionally.

Script to place files in folder by extracting date from filename

I know this has been asked many times, i am terrible with bash and i do not understand the regex format for it. Figured i'd ask for help..
I have a security camera which writes files to a folder in this format:
MDalarm_20170320_084514.mkv
so it goes -- MDalarm_yearmonthday_hourminutesecond.mkv
I want to create a cronjob that will run a script to clean this up, by doing the following:
Taking the files and placing them in a folder for year/month/day then renaming the file to the time only ie: 08_26_15.mkv, even 082615.mkv would be fine if too much of a hassle.
So in the example of MDalarm_20170320_084514.mkv
it should produce
/2017/03/20/08_45_14.mkv
or similar.
The files will be placed in the root folder as they come and the script will run once/twice a day on the folder for cleanup.
I'm decent with regex in php/js/etc.. but the bash one i completely do not understand well enough to get this done. I sincerely appreciate the help.
Cheers!
Use this to make the desired file name
$echo MDalarm_20170320_084514.mkv | sed -E "s/^MDalarm_[[:digit:]]{8}_//"
084514.mkv
and this to make the desired folder name
$echo MDalarm_20170320_084514.mkv | sed -E "s/^MDalarm_([[:digit:]]{4})([[:digit:]]{2})([[:digit:]]{2})_.*$/\/\1\/\2\/\3/"
/2017/03/20
Use them in shell commands to make folder (if needed) and copy/rename/move file.
This is what i ended up with and it works, thank you Yunnosch for the regex.
#!/bin/bash
if [[ `ls | grep -c mkv` == 0 ]]
then
echo "NO MKV FILES"
else
for f in *.mkv; do
name=`echo "$f"| sed -E "s/^MDalarm_[[:digit:]]{8}_([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})(.*)$/\1h-\2m-\3s\4/"`
dir=`echo "$f" | sed -E "s/^MDalarm_([[:digit:]]{4})([[:digit:]]{2})([[:digit:]]{2})_.*$/\1\/\2\/\3/"`
mkdir -p "$dir"
mv "$f" "$name"
mv "$name" "$dir"
done
fi
Once someone wrote the regex out i figured out the format, different yet similar.

Using xargs, eval, and mv ensemble

I've been using the command line more frequently lately to increase my proficiency. I've created a .txt file containing URLs for libraries that I'd like to download. I batch-downloaded these files using
$ cat downloads.txt | xargs wget
When using the wget command I didn't specify a destination directory. I'd like to move each of the files that I've just downloaded into a directory called "vendor".
For the record, it has occurred to me that if I ran...
$ open .
...I could drag-and-drop these files into the desired directory. But in my opinion that would defeat the purpose of this exercise.
Now that I have the files in my cwd, I'd like to be able to target them and move them into the "vendor" directory.
As a side-question: Is there a useful way to print the most recently created files to STDOUT? Currently, I can grab the filenames from the URLs within downloads.txt pretty simply using the following pipeline and Perl script...
$ cat downloads.txt | perl -n -e 'if (/(?<=\/)([-.a-z]+)$/) { print $1 . "\n" }'
This will produce...
react.js
redux.js
react-dom.js
expect.js
...which is great as these are file that I intended on targeting. I'd like to transform each of these lines into a command within a pipeline that resembles this...
$ mv {./,./vendor/}<filename>
... where <filename> is "react.js" then "redux.js", and so forth.
I figure that I may be able to accomplish this using some combination of xargs, eval, and mv. This is where my bash skills drop-off.
Just to reiterate, I'm aware that the method in which I am approaching this problem is neither simple nor ideal. This is intentionally a convoluted exercise intended to stretch my bash knowledge.
Is there anyone who knows how I can use xargs, eval, and mv to accomplish this goal?
Thank you!
xargs -l -a downloads.txt basename | xargs -i mv {} ./vendor
How this works: The first instance of xargs reads the file names from downloads.txt and calls basename for each of these file names individually (alternatively, you could use basename -a). These basenames are then piped to another instance of xargs, which uses the arguments to call mv, replacing the string {} with the current argument.
mv $(basename -a $(<downloads.txt)) ./vendor
How this works: Since you want to move all the files into the same directory, you can use a single call to mv. The command substitution ("backticks") inserts the output of the command basename -a, which, in turn, reads its arguments from the file.

Copying html files to create erb versions with bash script

I'm trying to write a bash (OSX) script that finds all html files in a directory and copies them to create erb files with underscores at the beginning of the file name. So test1.html would become _test1.html.erb for instance.
I was trying to do it a bit like this but there's probably a better way (and this way isn't finished)
find . -regex '.*/[^_].*\.html$' | while read file; do [need to do the copy X.html file to create new _X.html.erb file in here]; done
Any ideas?
Thanks!
Here is a for loop version:
for file in *html ; do
cp ${file} _${file}.ebr
done
and here is a find version:
find ./ -name "*html" -exec sh -c 'cp {} _$(basename {}).ebr' \;
find *.html | while read files
do
newname="_${files}.erb"
mv -v "${files}" "${newname}"
done

Copy and Rename Multiple Files with Regular Expressions in bash

I've got a file structure that looks like:
A/
2098765.1ext
2098765.2ext
2098765.3ext
2098765.4ext
12345.1ext
12345.2ext
12345.3ext
12345.4ext
B/
2056789.1ext
2056789.2ext
2056789.3ext
2056789.4ext
54321.1ext
54321.2ext
54321.3ext
54321.4ext
I need to rename all the files that begin with 20 to start with 10; i.e., I need to rename B/2022222.1ext to B/1022222.1ext
I've seen many of the other questions regarding renaming multiple files, but couldn't seem to make it work for my case. Just to see if I can figure out what I'm doing before I actually try to do the copy/renaming I've done:
for file in "*/20?????.*"; do
echo "{$file/20/10}";
done
but all I get is
{*/20?????.*/20/10}
Can someone show me how to do this?
You just have a little bit of incorrect syntax is all:
for file in */20?????.*; do mv $file ${file/20/10}; done
Remove quotes from the argument to in. Otherwise, the filename expansion does not occur.
The $ in the substitution should go before the bracket
Here is a solution which use the find command:
find . -name '20*' | while read oldname; do echo mv "$oldname" "${oldname/20/10}"; done
This command does not actually do your bidding, it only prints out what should be done. Review the output and if you are happy, remove the echo command and run it for real.
Just wanna add to Explosion Pill's answer.
On OS X though, you must say
mv "${file}" "${file_expression}"
Or the mv command does not recognize it.
Brace expansions like :
{*/20?????.*/20/10}
can't be surrounded by quotes.
Instead, try doing (with Perl rename) :
rename 's/^10/^20/' */*.ext
You can do this using the Perl tool rename from the shell prompt. (There are other tools with the same name which may or may not be able to do this, so be careful.)
If you want to do a dry run to make sure you don't clobber any files, add the -n switch to the command.
note
If you run the following command (linux)
$ file $(readlink -f $(type -p rename))
and you have a result like
.../rename: Perl script, ASCII text executable
then this seems to be the right tool =)
This seems to be the default rename command on Ubuntu.
To make it the default on Debian and derivative like Ubuntu :
sudo update-alternatives --set rename /path/to/rename
The glob behavior of * is suppressed in double quotes. Try:
for file in */20?????.*; do
echo "${file/20/10}";
done