How to remove first 16 characters of all file names in a directory? - rename

I have a directory with many files with really long, repetitive names and I would like to remove the first 16 characters from each file name.
So I would like to rename files like this:
0123456789012345file1.fits
0123456789012345file2.fits
to this:
file1.fits
file2.fits
I would like to be able to do this from the command line in the terminal.

In bash, you can run
for f in *; do mv "$f" "${f:16}"; done
to rename all files stripping off the first 16 characters of the name.
You can change the * to a more restrictive pattern such as *.fits if you don't want to rename all files in the current directory. The quotes around the parameters to mv are necessary if any filenames contain whitespace.
bash's ${var:pos:len} syntax also supports more advanced usage than the above. You can take only the first five characters with ${f::5}, or the first five characters after removing the first 16 characters with ${f:16:5}. Many other variable substitution expressions are available in bash; see a reference such as TLDP's Bash Parameter Substitution for more information.

Related

Delete files in a variable - bash

i have a variable of filenames that end with a vowel. I need to delete all of these files at once. I have tried using
rm "$vowels"
but that only seems to return the files within the variable and state that there is "No such file or Directory"
Its your use of quotes: they tell rm that your variables contents are to be interpreted as a single argument (filename). Without quotes the contents will be broken into multiple arguments using the shell rules in effect.
Be aware that this can be risky if your filenames contain spaces - as theres no way to tell the difference between spaces between filenames, and spaces IN filenames.
You can get around this by using an array instead and using quoted array expansion (which I cant remember the syntax of, but might look something like rm "${array[#]}" - where each element in the array will be output as a quoted string).
SOLUTION
assigning the variable
vowel=$(find . -type f | grep "[aeiou]$")
removing all files within variable
echo $vowel | xargs rm -v

How to iterate over files with quotes in filename?

I have set of files in /home/user/source. One file in this set has name 'e e' (with single quotes). When I tried to loop over this set of files and print all filenames I got this file with name e e (quotes disappered). How write this loop to save this quotes in output? Here is the code:
#!/bin/bash
for existedFile in "$(ls /home/user/source)"
do
echo $existedFile
done
Confused moment here is when I just use ls /home/user/source output is correct.
Don't Parse the Output of ls
The output of ls can contain anything. It can contain whitespace, newlines, commas, pipe symbols, etc. This can be extremely harmful in a script.
Instead, iterate over a glob: *. An asterisk is shorthand for "everything in this directory". Bash will take care of the iteration over files. If you need to match a particular file type/pattern, you can use *.java, file*.f90, etc.

Deleting files ending with 2 digits in linux

In my folder, I want to delete the files that ends with 2 digits (10, 11, 12, etc.)
What I've tried is
rm [0-9]*
but it seems like it doesn't work.
What is the right syntax of doing this?
Converting comments into an answer.
Your requirement is a bit ambiguous. However, you can use:
rm -i *[0-9][0-9]
as long as you don't mind files ending with three digits being removed. If you do mind the three-digit files being removed, use:
rm -i *[!0-9][0-9][0-9]
(assuming Bash history expansion doesn't get in the way). Note that if you have file names consisting of just 2 digits, those will not be removed; that would require:
rm -i [0-9][0-9]
Caution!
The -i option is for interactive. It is generally a bad idea to experiment with globbing and rm commands because you can do a lot of damage if you get it wrong. However, you can use other techniques to neutralize the danger, such as:
echo *[!0-9][0-9]
which echoes all the file names, or:
printf '%s\n' *[!0-9][0-9]
which lists the file names one per line. Basically, be cautious when experimenting with file deletion — don't risk making a mistake unless you know you have good backups readily available. Even then, it is better not to need to use them
See also the GNU Bash manual on:
Pattern matching — which notes you might be able to use ^ in place of !.
The shopt built-in
The command
rm [0-9]*
means remove all the files that start with a digit. The range within [] is expanded single time.
Whereas you intend to remove files ending with double digit, so command should be
rm *[0-9][0-9]
If you have some file extension, the command should be modified as
rm *[0-9][0-9]* or
rm *[0-9][0-9].ext
where ext is the extension like txt

Shell script to update last character of the filename

I have files in directories and sub directories, the filename should be changed such that, the last character should be replaced to a number or a character depending upon arguments provided. I could do it for numbers but not happening for a character.
For eg. if File names are 20170504ABCDXXXYYY6.xml or 20170504CFLFXXXYYY6.cfl.bz2.
If I write the command ./updateLastCharacter 5, file names should be 20170504ABCDXXXYYY5.xml or 20170504CFLFXXXYYY5.cfl.bz2.
If the command is ./updateLastCharacter A, file names should be 20170504ABCDXXXYYYA.xml or 20170504CFLFXXXYYYA.cfl.bz2.
I'm new to shell scripting. I tried a lot for making it happen but what I could do is :
find $directory -exec rename "s/[0-9].xml/$newNumber.xml/;s/[0-9].cfl/$newRevisionNumber.cfl/" {} ";"
This works fine for number but I'm looking for how can I do it for a character with single line command.
A simple solution with rename ( perl function )
find . | rename -n -v 's/[A-Za-z0-9](?=\.)/5/'
-n means no action
-v means verbose to the screen
And you can use renrem program utility directly that is more powerful than rename in Perl.
I wrote that program to myself because I needed a lot to rename or remove files.

bash - run script based on substring of filename (perhaps using wildcard)

I've got the below simple script that calls an external script with a number of filenames and arguments of either a delimiter or a set of cut positions. My question: is there a way to make the filename 'dynamic using wildcards' in the sense that the directory will always contain those filenames but with extra text on either end? But the script can do some sort of match up to get the full filename based on a 'contains'.
current /release/ext/ directory contents:
2011storesblah.dat
hrlatest.dat
emp_new12.txt
ie the directory contains these files today (but next week the filenames in this directory could have a slightly different prefix.
eg:
stores_newer.dat
finandhr.dat
emps.txt
Script:
#!/bin/bash
FILES='/release/ext/stores.dat "|"
/release/ext/emp.txt 1-3 4-11 15-40
/release/ext/hr.dat "|" 2'
for f in $FILES
do
echo `sh myexternalscript.sh $f`;
done
Note: there is no need to handle a scenario where the file in my script matches more than 2 files in the direc (it will always only match one).
Also it only can match the file types that are specified in the script.
Also, I don't need to search recursively, just needs to look in the /release/ext/ directory only.
I'm running SunOS 5.10.
$FILES=`find /release/ext -name *stores*.dat`
for FILE in $FILES do
# need to test for empty, case $FILES is empty
test -n "$FILE" && /do/whatever/you/want
done;
It is unclear what the pipe characters and numbers are for in your $FILES variable. However, here is something you might find useful:
#!/bin/bash
filespecs='*stores*.dat *hr*.dat *emp*.txt'
dir='/release/ext'
cd "$dir"
for file in $filespecs
do
sh myexternalscript.sh "$dir/$file"
done
Note that your question is tagged "bash" and you use "bash" in your shebang, but for some reason, you use "sh" when you call your other script. On some systems, sh is symlinked to Bash, but it will behave differently than Bash when called directly. On many systems, sh is completely separate from Bash.
In order to expand the globs and incorporate other arguments, you will need to violate the Bash rule of always quoting variables (this is an example of one of the exceptions).
filespecs='*stores*.dat | 3
*hr*.dat 4 5
*emp*.txt 6 7 8'
while read -r spec arg1 arg2 arg3 arg4
do
sh myexternalscript.sh "$dir"/$spec "$arg1" "$arg2" "$arg3" "$arg4"
done < <(echo "$filespecs")
Use as many "arg" arguments as you think you'll need. Extras will be passed as empty, but set arguments. If there are more arguments than variables to accept them, then the last variable will contain all the remainders in addition to the one that corresponds to it. This version doesn't need the cd since the glob isn't expanded until the directory has been prepended, while in the first version the glob is expanded before the directory is prepended.
If you quote the pipes in the manner shown in your question, then the double quotes will be included in the argument. In the way I show it, only the pipe character gets passed but it's protected since the variable is quoted at the time it's referenced.

Resources