Rename file in Unix using part of the filename - file

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

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

Rename Multiple files in a Unix Directory by removing characters

I would like to rename Multiple files in a Unix Directory using Ksh Command.
Eg ATT8-2011-10-01 00:00:00-MSA-IMM-SINGLE_AND_FAMILY_COVERAGE-DED-$2000-X114817.PDF
needs to be renamed as
ATT8-2011-10-01-MSA-IMM-SINGLE_AND_FAMILY_COVERAGE-DED-$2000-X114817.PDF
Basically the time portion which is always 00:00:00 needs to be stripped off and the space between the date and the next hyphen symbol (-) needs to be compressed.
Any ideas as to how to this ? Assuming they are about 3000 files in the directory.
On some systems, there is a Perl-based rename command (sometimes called prename) and you'd write:
rename 's/ 00:00:00//' *" 00:00:00-"*
If you don't have that, find it. If you can't find it, then you have more work to do. However, the work is searching on SO. For example, Underscore in rename command (Perl and Unix shell) has a link to one version of the prename (Perl rename) command.

IBM i PASE tar - Excluding files or directories

I want to exclude some directories from an archive using the PASE tar command on an IBMi but the [-X Exclude File] option doesn't seems to work for me.
I tried using an exclude file that just contained a file name (/home/JSMITH/data/sub2/file2.txt) and then one that just contained a pattern (*.txt), and neither archive operation omitted anything.
Given the following directory structure:
/home/JSMITH/data
/home/JSMITH/data/sub1
/home/JSMITH/data/sub1/file1.txt
/home/JSMITH/data/sub2
/home/JSMITH/data/sub2/file2.txt
/home/JSMITH/data/sub3
/home/JSMITH/data/sub3/file3.txt
and the following command:
/qopensys/usr/bin/tar -cvf /home/JSMITH/test.tar -X /home/JSMITH/excludes.txt /home/JSMITH/data
The entire /home/JSMITH/data structure gets included in the resulting archive.
I have tried using the /home/JSMITH/excludes.txt file with either of these contents:
/home/JSMITH/data/sub2/file2.txt
or
*.txt
How does one exclude files/directories/patterns from the IBMi PASE tar command?
You need the full path in the exclude file.
I created mine via ls /home/JSMITH/data/*.txt > /home/JSMITH/excludes.txt
If you're doing it by hand, make certain you haven't got any trailing whitespace.
Also, I used Notepad++ when I created mine by hand. I found that the green screen edtf created an EBCDIC file with CRLF in it, and that didn't exclude for me.
IBM i 7.1

Delete all files except

I have a folder with a few files in it; I like to keep my folder clean of any stray files that can end up in it. Such stray files may include automatically generated backup files or log files, but could be a simple as someone accidentally saving to the wrong folder (my folder).
Rather then have to pick through all this all the time I would like to know if I can create a batch file that only keeps a number of specified files (by name and location) but deletes anything not on the "list".
[edit] Sorry when I first saw the question I read bash instead of batch. I don't delete the not so useful answer since as was pointed out in the comments it could be done with cygwin.
You can list the files, exclude the one you want to keep with grep and the submit them to rm.
If all the files are in one directory:
ls | grep -v -f ~/.list_of_files_to_exclude | xargs rm
or in a directory tree
find . | grep -v -f ~/.list_of_files_to_exclude | xargs rm
where ~/.list_of_files_to_exclude is a file with the list of patterns to exclude (one per line)
Before testing it make a backup copy and substitute rm with echo to see if the output is really what you want.
White lists for file survival is an incredibly dangerous concept. I would strongly suggest rethinking that.
If you must do it, might I suggest that you actually implement it thus:
Move ALL files to a backup area (one created per run such as a directory containing the current date and time).
Use your white list to copy back files that you wanted to keep, such as with copy c:\backups\2011_04_07_11_52_04\*.cpp c:\original_dir).
That way, you keep all the non-white-listed files in case you screw up (and you will at some point, trust me) and you don't have to worry about negative logic in your batch file (remove all files that _aren't of all these types), instead using the simpler option (move back every file that is of each type).

Cat selected files fast and easy?

I have been cat'ing files in the Terminal untill now.. but that is time consuming when done alot. What I want is something like:
I have a folder with hundreds of files, and I want to effectively cat a few files together.
For example, is there a way to select (in the Finder) five split files;
file.txt.001, file.txt.002, file.txt.003, file.txt.004
.. and then right click on them in the Finder, and just click Merge?
I know that isn't possible out of the box of course, but with an Automator action, droplet or shell script, is something like that possible to do? Or maybe assigning that cat-action a keyboard shortcut, and when hit selected files in the Finder, will be automatically merged together to a new file AND placed in the same folder, WITH a name based on the original split files?
In this example file.001 through file.004 would magically appear in the same folder, as a file named fileMerged.txt ?
I have like a million of these kind of split files, so an efficient workflow for this would be a life saver. I'm working on an interactive book, and the publisher gave me this task..
cat * > output.file
works as a sh script. It's piping the contents of the files into that output.file.
* expands to all files in the directory.
Judging from your description of the file names you can automate that very easily with bash. e.g.
PREFIXES=`ls -1 | grep -o "^.*\." | uniq`
for PREFIX in $PREFIXES; do cat ${PREFIX}* > ${PREFIX}.all; done
This will merge all files in one directory that share the same prefix.
ls -1 lists all files in a directory (if it spans multiple directories can use find instead. grep -o "^.*\." will match everything up to the last dot in the file name (you could also use sed -e 's/.[0-9]*$/./' to remove the last digits. uniq will filter all duplicates. Then you have something like speech1.txt. sound1.txt. in the PREFIXES variable. The next line loops through those and merges the groups of files individually using the * wildcard.

Resources