How to set file's DateTimeOriginal from file name using ExifTool - batch-file

I have a directory with many image files that don't have their DateTimeOriginal metadata set, but do have this date in the file name itself in the format of YYYMMDD, e.g. 20120524_091536.mp4
I want to use exiftool to move these files into folders with the year and then sub-folders of the month (then later also set its DateTimeOriginal using this date from the filename).
Something like this:
exiftool -d "%Y-%m-%d" "-testname<D:\Pictures\${filename#;DateFmt('%Y')}\${filename#;DateFmt('%m')}\$FileName" "D:\Pictures\2012-05-24" -r
But this gives an Error converting date/time for 'filename' error. Which makes sense, how do I tell it to format only the first 8 digits of the filename to a date?
The reason I want to use ExifTool for this, is that I actually am going to further refine this statement to only do this for files that don't already have a datetimeoriginal metadata set, so exiftool can filter these out...something like this qualifier:
exiftool '-datetimeoriginal<filemodifydate' -if '(not $datetimeoriginal or ($datetimeoriginal eq "0000:00:00 00:00:00")) and ($filetype eq "JPEG")'
But instead of setting the datetimeoriginal to the filemodifydate, I need to set it to a date formatted from the filename.

To set DateTimeOriginal from the filename, the command is as simple as
exiftool "-DateTimeOriginal<Filename" -if "not $datetimeoriginal or ($datetimeoriginal eq '0000:00:00 00:00:00')" -ext jpg DIR
This is based upon Exiftool FAQ #5 which says "ExifTool is very flexible about the actual format of input date/time values when writing, and will attempt to reformat any values into the standard format unless the -n option is used. Any separators may be used (or in fact, none at all). The first 4 consecutive digits found in the value are interpreted as the year, then next 2 digits are the month, and so on."
I removed the $filetype eq "JPEG" portion of your example and replaced it with the -ext option as checking against Filetype is a poor way to limit the files processed, as exiftool will still process and extract all metadata from every file to perform the check.
Take note that the .mp4 filetype, as shown in your example, cannot hold the DateTimeOriginal tag. Instead, you'll have to use something like CreateDate. Also take note that exiftool has limited ability to write to video files.
Because the filename isn't a timestamp type tag, you can't use the -d (dateformat) option as you discovered. Instead, you would have to use the Advanced formatting feature to split up the filename. Given the first example filename, your command would be:
exiftool "-testname<D:\Pictures\${filename;s/^(\d{4}).*/$1/}\${filename;s/^\d{4}(\d\d).*/$1/}\%F" "D:\Pictures\2012-05-24" -r
The -d "%Y-%m-%d" part is removed as it wasn't used in your example. ${filename;s/^(\d{4}).*/$1/} uses regex to match the first four digits of the filename and strip the rest. ${filename;s/^\d{4}(\d\d).*/$1/} strips the first four digits, matches the next two, and strips the rest of the filename. %F is an exiftool variable for the filename+ext used for the various exiftool file operations such as renaming and moving (but not available in tag processing).

Related

Rename file in Unix using part of the filename

How do I rename all files in a folder in Unix with part of the filename? Basically I want to use the string before the first hyphen to rename the file.
Current Filename Format:
ABC_XYZ-2022-11-09_07.52.03.csv
ABCD_XYZ-2022-11-09_07.52.03.csv
ABCDEF_XY-2022-11-09_07.52.03.csv
Desired format:
ABC_XYZ.csv
ABCD_XYZ.csv
ABCDEF_XY.csv
I am new in Unix and have no idea how to do it
for i in *.csv
do
mv -i "$i" "${i%%-*}".csv
done
${i%%-*} is the value of variable i with the longest string matching -* removed from its end. This also removes the .csv or any other .* ending.
I used mv -i to get a prompt in case the target file already exists. This could happen if two file names differ only in the date/time part.
If you have files with different endings you want to keep, a POSIX compatible solution might get a bit more complicated.
If all files contain a . after the part you want to remove and if you use bash, you can also use
for i in *
do
mv -i "$i" "${i/-*./.}"
done

VLC command line converting is not always working

I scheduled a .cmd file that would convert a network stream into a .mp4 file, using:
vlc -vvv "http://86.127.212.113/control/faststream.jpg?stream=mxpeg" --sout=#transcode{vcodec=h264,scale=Automat,scodec=none}:file{dst=C:\\Users\\ACV\\Videos\\rec3.mp4,no-overwrite} :no-sout-all :sout-keep
It often works, but sometimes it just creates big files that I am not able to play.
Even VLC itself cannot play these files, outputting just this
I would suggest that you use the following syntax:
Replace the = after --sout with a space character
Doublequote the --sout chain
Replace the prefix : characters for the global options for no-sout-all and sout-keep with --
#"%ProgramFiles%\VideoLAN\VLC\vlc.exe" -vvv "http://86.127.212.113/control/faststream.jpg?stream=mxpeg" --sout "#transcode{vcodec=h264,scale=Automat,scodec=none}:file{dst=C:\\Users\\ACV\\Videos\\rec3.mp4,no-overwrite}" --no-sout-all --sout-keep
I have included the full path to vlc.exe for safety, please adjust it as you need.

How to modify single digit hour to two digit hour in a specific date/time field value in a CSV file?

I have a text file (.txt) that contains multiple rows of text in the following format:
ABCD|TEST|123456|12/10/2017 5:41|Sample|CODENOTE123|Comment text|11/27/2017|12383697
As it can be seen, there are 9 columns separated by the pipe | operator. I need to edit the time, i.e. 5:14, and convert it to 05:14. If the hour has already two digits, no changes need to be made to the row.
The date and time will always be the 4th column element.
The line after editing should look like as follows:
ABCD|TEST|123456|12/10/2017 05:41|Sample|CODENOTE123|Comment text|11/27/2017|12383697
This editing has to be done for each row in the text file and a new text file has to be created with all the rows containing the correct time format.
PS: The number of columns (separated by the pipe operator) can be between 9 to 14, but the date and time will always appear in the 4th column.
The Windows command interpreter executing a batch file is designed for running commands and executables, but not for editing text or binary files. Therefore nearly all other scripting or programming languages are better for this CSV file editing task.
How can you find and replace text in a file using the Windows command-line environment? contains lots of solutions for searching and replacing strings in a file mainly using applications or other scripting languages.
One of the provided solutions is JREPL.BAT written by Dave Benham which is a batch file / JScript hybrid. Microsoft's JScript supports regular expression replaces. So whenever a simple regular expression search and replace in Perl like regex syntax can be performed on a text file with a text editor, it can be done usually also with jrepl.bat from within a batch file.
The batch code below expects jrepl.bat in same directory as the batch file containing the posted command lines. The file to modify is specified twice in this batch file with name DataFile.csv.
#echo off
if not exist "DataFile.csv" goto :EOF
if not exist "%~dp0jrepl.bat" goto :EOF
call "%~dp0jrepl.bat" "(\|[01][0-9]/[0-3][0-9]/(?:19|20)[0-9][0-9]) (?=[0-9]:[0-5][0-9]\|)" "$1 0" /F "DataFile.csv" /O -
The search expression is written to find a date with time between two | in format MM/DD/YYYY h:mm and inserts 0 after the space character before single digit hour. Century of year must be 19 or 20.
The search string finds the date/time in this format anywhere in line because I think this is better for the future in case of date/time string ever changes its field position in the line. It would be also possible to limit this search/replace to fourth | delimited field value with the search string:
^((?:[^|]*\|){3}[01][0-9]/[0-3][0-9]/(?:19|20)[0-9][0-9]) (?=[0-9]:[0-5][0-9]\|)
DataFile.csv is modified directly by this batch script. Replacing - at end of jrepl.bat command line by a file name produces a new file being a copy of DataFile.csv with all hour values converted to two digit values.

Repl.bat to find and replace text from a list of files

This is a follow on from Batch file to list txt and mp3 files - using the list extract the same lines from the text files
Basically I create a list of text files, then using this list find a line in the text files called "JobNotes=" and output that to a new file with the inforamtion in the Job notes displayed in a different fashion.
I have modified the code to use the findstr on a list of files (file names are in a file text_list). It creates the first output file fine but then diplays the other output files incorrectly.
This is the code
for /f "delims=" %%f in (%text_list%) do (
FINDSTR /l "^Job Notes=" "%%f" |repl.bat ".*=(.*) (\d+) (\d+\/\d+\/\d+) \d+:\d+:\d+ .*" "Name=$1\r\nFile Number=$2\r\nDate=$3" x >"C:\replacer\move\%%f"
)
This is the fist output file (which is displayed correctly).
Name=John Smith
File Number=123456
Date=22/11/2013
Then all other output files diaply like this (which is the way it is diplayed in the input file).
Job Notes=Jane Smith 234567 22/11/2013 1:22:33 PM 654321
Thanks for the help
First, an unrelated problem with your FINDSTR - It is not operating as you intended. You are looking for lines that begin with Job Notes=, but instead it is looking for any line that contains the string ^Job or Notes=. FINDSTR breaks strings at spaces unless the /C:"literal search string" option is used. Your FINDSTR code apparently gives the correct results because only wanted lines contain the string Notes=, but you might not want to rely on that.
You can fix it by using a corrected literal search string:
FINDSTR /bc:"Job Notes:" ...
or a corrected regular expression:
FINDSTR /rc:"^Job Notes:" ...
Regarding your actual question - REPL.BAT will only modify lines that match the supplied search string; unmatched lines are left as is. You can eliminate unmatched lines by appending the A option (altered lines only). But that only hides the problem in your case.
The solution is to modify the regex search string so that it properly matches all input lines.
I suspect that your actual data does not contain Job Notes=Jane Smith 234567 22/11/2013 1:22:33 PM 654321, as that line is properly modified by your existing code.
In order for anyone to help you, you must be more precise as to the format of each line (including all variations). Please post some example lines that are not working, along with some that do. Don't change anything, except perhaps modify the letters in the names, and perhaps scramble the numbers - but do not change the count or type of characters in any position.
One other point - the FINDSTR command can probably be dropped with the correct REPL.BAT regex and the addition of the A option.

filename contains space and wildcard in a variable

I receive files which names contain spaces and change every week (the name contains the week number)
IE, the file for this week looks like This is the file - w37.csv
I have to write a script to take this file into account.
I didn't succeed in writing this script.
If I do :
$FILE="This is the file - w*.csv"
I don't find /dir/${FILE}
I tried "This\ is\ the\ file - w*.csv"
I tried /dir/"${FILE}" and "/dir/${FILE}"
But I still can't find my file
It looks like the space in the name needs the variable to be double-quoted but, then, the wildcard is not analysed.
Do you have an idea (or THE answer)?
Regards,
Olivier
echo /dir/"This is the file - w"*.csv
or — you almost tried that —
echo /dir/This\ is\ the\ file\ -\ w*.csv
Use a bash array
v=( /dir/This\ is\ the\ file - w*.csv )
If there is guaranteed to be only one matching file, you can just expand $v. Otherwise, you can get the full list of matching files by expanding as
"${v[#]}"
or individual matches using
"${v[0]", "${v[1]}", etc
First of all, you should not use the dollar sign in an assignment.
Moreover, wildcard expansion is not called in an assignment. You can use process substitution for example, though:
FILE=$(echo 'This is the file - w'*.csv)
Note that the wildcard itself is not included in the quotes. Quotes prevent wildcard expansion.

Resources