Bash script to remove 'x' amount of characters the end of multiple filenames in a directory?
mv $filname $(echo $filename | sed -e 's/.....\.moc1$//');
or
echo ${filename%%?????.moc1}.moc1
%% is a bash internal operator...
How do I truncate the last two characters of all files in a directory?
With Perl's standalone rename command:
rename -n 's/..(\....)$/$1/' *
If everything looks fine, remove -n
.
It is possible to use this standalone rename
command with a syntax similar to sed
's s/regexp/replacement/
command. In regex a .
matches one character. \.
matches a .
and $
matches end of line (here end of filename). (
and )
are special characters in regex to mark a subexpression (here one .
and three characters at the end of your filename) which then can be reused with $1
. sed
uses \1
for first back-reference, rename uses $1
.
See: Back-references and Subexpressions with sed
Delete files with a length of x or more characters
Since the question can have 2 interpretations, both answers are given:
1. To delete files with 6 or more characters in the FILE NAME:
rm ??????*
Explanation:
??????
: The?
's are to be entered literally. Each?
matches any single character. So here it means "match any 6 characters"*
: The*
wildcard matches zero or more characters- Therefore it removes any file with 6 or more characters.
Alternatively:
find -type f -name "??????*" -delete
Explanation:
find
: invoke the find command-type f
: find only files.-name "??????*"
: match any file with at least 6 characters, same idea as above.-delete
: delete any such files found.
2. To delete files with 6 or more characters in its CONTENTS:
find -type f -size +5c -delete
Explanation:
find
: invoke the find command-type f
: find only files (not directories etc)-size +5c
: find only files greater than 5 characters long. Note: recall thatEOF
(end of file) counts as a character in this case. If you'd like to excludeEOF
from your counter, change it from 5 to 6.-delete
: delete any such files found
Rename and remove every character before _ for multiple files in a folder
You can use bash-internal parameter pattern substitution:
$ f='random text _987media.mp4'
$ echo "${f/*_/}"
987media.mp4
to remove everything before the last underscore, underscore included.
To rename all files containing an _
, in bulk:
find . -type f -name "*_*" -exec bash -c 'f="$1"; g="${f/*_/}"; mv -- "$f" "$g"' _ '{}' \;
Rename file by removing last n characters
You can remove a fixed number of characters using
mv "$file" "${file%???????}" # 7 question marks to match 7 characters
This will work in any POSIX-compliant shell.
To remove the last extension (which may be more or less than 7 characters), use
mv "$file" "${file%.*}"
To trim everything after a given extension, you can try
EXT=csv
mv "$file" "${file%.$EXT.*}".$EXT
which actually removes .$EXT
and everything after, but then reattaches .$EXT
.
How to remove last n characters from a string in Bash?
First, it's usually better to be explicit about your intent. So if you know the string ends in .rtf
, and you want to remove that .rtf
, you can just use var2=${var%.rtf}
. One potentially-useful aspect of this approach is that if the string doesn't end in .rtf
, it is not changed at all; var2
will contain an unmodified copy of var
.
If you want to remove a filename suffix but don't know or care exactly what it is, you can use var2=${var%.*}
to remove everything starting with the last .
. Or, if you only want to keep everything up to but not including the first .
, you can use var2=${var%%.*}
. Those options have the same result if there's only one .
, but if there might be more than one, you get to pick which end of the string to work from. On the other hand, if there's no .
in the string at all, var2
will again be an unchanged copy of var
.
If you really want to always remove a specific number of characters, here are some options.
You tagged this bash
specifically, so we'll start with bash builtins. The one which has worked the longest is the same suffix-removal syntax I used above: to remove four characters, use var2=${var%????}
. Or to remove four characters only if the first one is a dot, use var2=${var%.???}
, which is like var2=${var%.*}
but only removes the suffix if the part after the dot is exactly three characters. As you can see, to count characters this way, you need one question mark per unknown character removed, so this approach gets unwieldy for larger substring lengths.
An option in newer shell versions is substring extraction: var2=${var:0:${#var}-4}
. Here you can put any number in place of the 4
to remove a different number of characters. The ${#var}
is replaced by the length of the string, so this is actually asking to extract and keep (length - 4) characters starting with the first one (at index 0). With this approach, you lose the option to make the change only if the string matches a pattern; no matter what the actual value of the string is, the copy will include all but its last four characters.
You can leave the start index out; it defaults to 0, so you can shorten that to just var2=${var::${#var}-4}
. In fact, newer versions of bash (specifically 4+, which means the one that ships with MacOS won't work) recognize negative lengths as the index of the character to stop at, counting back from the end of the string. So in those versions you can get rid of the string-length expression, too: var2=${var::-4}
.
If you're not actually using bash but some other POSIX-type shell, the pattern-based suffix removal with %
will still work – even in plain old dash, where the index-based substring extraction won't. Ksh and zsh do both support substring extraction, but require the explicit 0 start index; zsh also supports the negative end index, while ksh requires the length expression. Note that zsh, which indexes arrays starting at 1, nonetheless indexes strings starting at 0 if you use this bash-compatible syntax. But zsh also allows you to treat scalar parameters as if they were arrays of characters, in which case the substring syntax uses a 1-based count and places the start and (inclusive) end positions in brackets separated by commas: var2=$var[1,-5]
.
Instead of using built-in shell parameter expansion, you can of course run some utility program to modify the string and capture its output with command substitution. There are several commands that will work; one is var2=$(sed 's/.\{4\}$//' <<<"$var")
.
Replace or delete certain characters from filenames of all files in a folder
Use PowerShell to do anything smarter for a DOS prompt. Here, I've shown how to batch rename all the files and directories in the current directory that contain spaces by replacing them with _
underscores.
Dir |
Rename-Item -NewName { $_.Name -replace " ","_" }
EDIT :
Optionally, the Where-Object
command can be used to filter out ineligible objects for the successive cmdlet (command-let). The following are some examples to illustrate the flexibility it can afford you:
To skip any document files
Dir |
Where-Object { $_.Name -notmatch "\.(doc|xls|ppt)x?$" } |
Rename-Item -NewName { $_.Name -replace " ","_" }To process only directories (pre-3.0 version)
Dir |
Where-Object { $_.Mode -match "^d" } |
Rename-Item -NewName { $_.Name -replace " ","_" }PowerShell v3.0 introduced new
Dir
flags. You can also useDir -Directory
there.To skip any files already containing an underscore (or some other character)
Dir |
Where-Object { -not $_.Name.Contains("_") } |
Rename-Item -NewName { $_.Name -replace " ","_" }
Related Topics
Why Redirect Stdin Inside a While Read Loop in Bash
Pattern Match Does Not Work in Bash Script
Gem5 Syscall Emulation Arm C Hello World Fails with "Fatal: Syscall Gettid (#224) Unimplemented"
Bash: Set Array Env Variable and De-Referencing It from Any Shell Script Fails
Getting Pids from Ps -Ef |Grep Keyword
What Linux Shell Command Returns a Part of a String
Finding Docker Container Processes? (From Host Point of View)
How to Delete All Lines in a File Starting from After a Matching Line
How to Detect the Physical Connected State of a Network Cable/Connector
How to Count Number of Files in Each Directory
How to Show a Gui Message Box from a Bash Script in Linux
How to Get 'Find' to Ignore .Svn Directories
Rsync Copy Over Only Certain Types of Files Using Include Option
Replace the First Line in a Text File by a String
Converting Serial Port Data to Tcp/Ip in a Linux Environment