filename contains space and wildcard in a variable - file

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.

Related

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

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).

How do I delete text before a pattern using a batch script

Using a batch script, how do I delete the following pattern from the start of a file?
DN: CN=ACME Test,OU=ACME Test Company,O=ACME Big Org someObject;binary:
There is a space character after binary: that needs deleting too.
The file contains:
DN: CN=ACME Test,OU=ACME Test Company,O=ACME Big Org someObject;binary: MI...
The ... indicates lots more character after the MI
I just need the MI and all the characters the follow it to be in the file after the batch script has run
I think what you are looking for is answered here
Batch script to find and replace a string in text file without creating an extra output file for storing the modified file
but instead of taking in the "replace=%2" as an argument and replacing with that, you can just replace with an empty string (or pass an empty string in as the parameter if it will never change)
with dcod's link you would have to know the first part of the string to replace it with nothing. His link is nearly fine, but to delete from the start to (including) binary;, instead of
set "line=!line:%search%=%replace%!"
use
set "line=!line:*binary: =!"

Remove some characters from filename using powershell

I have a 100 files Which are named for instance: (Without quotes)
"Managing and Improving Own Learning [L3] {CBA849}" and
"Note-taking and Note-making [L3] {CBA851}"
I would like to rename it in a such way that it only shows "CBA849" and "CBA851" and remove anything else.
Another words I would like to keep file code inside {....} curly brackets.
Is there a way we can implement this? (Note: It's not replacing characters)
Thanks
Rename-Item -LiteralPath $path ([regex]::match($path, '{(.+)}')).Groups[1].Value
You need -LiteralPath because the filename contains brackets.
[regex]::match($path, '{(.+)}') matches the curly braces and their contents, and captures the contents into a match group. .Groups[1].Value returns the value of the first (and in this case, the only) match group.
This assumes that all the files are named in the format shown in the question. If it's possible that there might be curly braces elsewhere in the name, change the regex {(.+)} to {(.+?)}$.
I'd personally use a Regex match:
GCI $path | ?{$_.Name -match "(?:.*?{)(.*?)(?:})(\..*)?$"}|%{$_.MoveTo("$($_.Directory)\$($matches[1])$($matches[2])")}
Edit: As Adi Inbar says, I have created an overly complicated RegEx pattern. Simplified as he suggested (though still allowing for extensions) is a revised answer:
GCI $path | ?{$_.BaseName -match "{(.*?)}$"}|%{$_.MoveTo("$($_.Directory)\$($matches[1])$($_.Extension)")}
Edit: Ok, here's the breakdown...
GCI is short for Get-ChildItem, it pulls a listing of the directory specified, but I think you probably figured that one out.
Then it pipes to a Where{} clause(? is an alias for Where). It matches the BaseName of the files and folders provided by the GCI command. The BaseName property is actually one generated by PowerShell that takes the name of the file, extension and all, and then removes the extension (with preceding period) from it so if the file name is Sample.txt then it provides you with Sample as the BaseName.
It matches that against a RegEx (short for Regular Expression) pattern. If you don't know what RegEx is, please feel free to look it up and read up on it (Google is your friend). The basics is that it matches a pattern instead of actual text. In this case the pattern is anything at the end of the file name that is between curly braces.
Past that it enters a ForEach loop (I used the % alias for ForEach). For each file that matched the RegEx pattern it performs the MoveTo() method for that file. The location that it is moving it to is that file's current directory (gotten with $.Directory), followed by a backslash, followed by $Matches[1] (I'll get to that in a second), and then the original extension of the file (gotten with $.Extension). Now you'll see I wrapped the Directory and Extension in a sub-expression $() because with string extrapolation (how it auto-magically expands variables if you put them within double quotes) if you try to specify a property of a variable you have to put it in a sub-expression. Otherwise it tries to expand just the variable itself, and shows the .Whatever property name in plain text.
Lastly, $Matches is an automatic variable that is populated when you make a match with a few things (such as <something> -match <something else> like we did in the Where clause). The first record of it is the whole string that was matched <something>, and then the next records are the matches based on <something else>.
I hope that clears it all up for you. If you have specific questions let me know. If this answer resolved your question please mark it as accepted.
$f=gi $filepath;
$f.MoveTo($f.fullname.Replace($f.name,$f.name.substring($f.name.indexof("{")+1,($f.name.indexof("}")-1)-$f.name.indexof("{"))+$f.extension))
Get the File you're looking to rename as a [System.IO.FileInfo] object using get-item (gi).
Once you have the file object in $f the script is doing:
MoveTo
$f.FullName: The full path of the existing file (C:\some\dir\Test {ABC123}.txt)
Modify FullName to be the new filename by using the Replace function to replace the old filename ($f.name), with the desired name
The Substring function of the filename will allow you to get just the string between the curly braces.
Find the index of the OpenCurlyBracket within the name string
Find the index of the CloseCurlyBracket within the name string
Once the text between the curly brackets is identified with the Substring function, append the file extension to the new filename

Bash - Source a file with "/"

I have a cache in the filesystem which I implemented this way.
To store a value I do something like
echo ""$KEY1"_"$KEY2"="$VALUE" >> $CACHE_DIR/$INDEX.cache
To get a value, first I source the cache file:
source $CACHE_DIR/$INDEX.cache
and then I echo the "$KEY1"_"$KEY2"
Cache example:
foo1_foo2=wohohhowwho
The problem with this, is that I have some keys that have a "/" in it, so when I have this:
foo3_foo/4=wohohhowwho
and source the file, it says
cache/15637.cache: line 1: foo3_foo/4=wohohhowwho: No such file or directory
because of the /.
Is there an option to the source command to not search in the path for files and only take in count the content as vars? I could escape the /, but is there another way?
There is no other way since / is not allowed as a character in bash variables.
you have to ``sanitize'' you key as bash only support for variable name: letter, digit and the underline character.
KEY1=${KEY1//\//_}
KEY2=${KEY2//\//_}

How to automatically remove the file extension in a file name

I am trying to make a script in bash that requires the removal of the the file extension from a file name, like the following
original: something.zip
removed version: something
And I was thinking I could use cut for this, but I am worried that a situation could arise where there might be a file name that has more than one period, etc, something similar to the following
something.v2.zip
having said that, I was wondering if anyone had any recommendations as to what I could do to just remove the last period and the text after it from a line of text/filename? any help would be appreciated, thanks!
f=file.zip
echo "${f%.zip}"
file
The '%' is a parameter modifier, it means, delete from the right side of the value of the variable whatever is after the '%' char, in this case, the string .zip. You can make this more general to remove any trailing extension, by using a wild card like
echo "${f%.*}"
file
If you want to remove the from the last period to the end, try this:
$ f=some.thing.zip
$ echo "${f%.*}"
some.thing

Resources