Bash script to remove last three charater in a file name - linux

For ex the file is this:
NBDG6_CDRCCN_4004_-TTNBDG6_CCN_51-140108-1433-802580.00.Blk32768Blk.CCN:00
I want to rename this file to:
NBDG6_CDRCCN_4004_-TTNBDG6_CCN_51-140108-1433-802580.00.Blk32768Blk.CCN

Using ${parameter%word} (Remove matching suffix pattern):
$ echo "$fn"
NBDG6_CDRCCN_4004_-TTNBDG6_CCN_51-140108-1433-802580.00.Blk32768Blk.CCN:00
$ echo "${fn%:*}"
NBDG6_CDRCCN_4004_-TTNBDG6_CCN_51-140108-1433-802580.00.Blk32768Blk.CCN

Using cut
$ echo $fn
NBDG6_CDRCCN_4004_-TTNBDG6_CCN_51-140108-1433-802580.00.Blk32768Blk.CCN:00
$ echo $fn |cut -d: -f1
NBDG6_CDRCCN_4004_-TTNBDG6_CCN_51-140108-1433-802580.00.Blk32768Blk.CCN
Using awk
echo $fn |awk -F : '{print $1}'
more ways...

According to the link here:
This should work:
awk '{old=$0;gsub(/...$/,"",$0);system("mv \""old"\" "$0)}'
provided the file name is given as input.
For eg:
ls -1 NBDG6_CDRCCN_4004_-TTNBDG6_CCN_51-140108-1433-802580.00.Blk32768Blk.CCN:00|nawk '{old=$0;gsub(/...$/,"",$0);system("mv \""old"\" "$0)}'

Rename file using bash string manipulations:
# Filename needs to be in a variable
file=NBDG6_CDRCCN_4004_-TTNBDG6_CCN_51-140108-1433-802580.00.Blk32768Blk.CCN:00
# Rename file
mv "$file" "${file%???}"
This removes the last three characters from filename.

Using just bash:
fn='NBDG6_CDRCCN_4004_-TTNBDG6_CCN_51-140108-1433-802580.00.Blk32768Blk.CCN:00'
mv "$fn" "${fn::-3}"

if you have Ruby
echo NBDG6_CD* | ruby -e 'f=gets.chomp;File.rename(f, f[0..-4])'

Related

Extracting a numbers from filenames

I have a bunch of files that all have a name and a serial number and an extension. I want to extract this serial number and extension. They look like this:
photo-123.jpg
photo-456.png
photo-789.bmp
etc.
I want to run a bash script to extract these serial numbers and place them in a file in this way:
123
456
789
etc.
Note that not all the photos have the same extension (bmp, png, jpg) but they all start with photo-.
You can use parameter substitution:
$ ls
photo-123.jpg photo-456.png photo-7832525239.bmp photo-789.bmp
$ for file in *; do
[[ -f "$file" ]] || continue
[[ $file == "num.log" ]] && continue
file=${file%.*} && echo "${file#*-}"
done > num.log
$ ls
num.log photo-123.jpg photo-456.png photo-7832525239.bmp photo-789.bmp
$ cat num.log
123
456
7832525239
789
${parameter#word} removes the shortest match from the start and ${parameter##word} removes the longest match from the start. ${parameter%word} on the contrary will remove shortest match from the end and ${parameter%%word} will remove longest match from the end.
Alternatively, you can read about nullglob instead of checking for existence of file in event there are no files in the directory. (Thanks Adrian Frühwirth for great feedback)
Using BASH regex:
f='photo-123.jpg'
[[ "$f" =~ -([0-9]+)\. ]] && echo "${BASH_REMATCH[1]}"
123
To run it against all the matching files:
for f in *-[0-9]*.*; do
[[ "$f" =~ -([0-9]+)\. ]] && echo "${BASH_REMATCH[1]}"
done
Assuming you just want to keep all of the numbers and you're using bash, here are a couple of things which you may find useful:
danny#machine:~$ file=abc123def.jpg
danny#machine:~$ echo ${file//[^0123456789]/}
123
danny#machine:~$ echo ${file##*.}
jpg
danny#machine:~$ echo ${file//[^0123456789]/}.${file##*.}
123.jpg
You should be able to write your script based on that. Or, just remove the leading "photo-" from $name by using
newname=$(name#photo-}
Those and several others are explained in the bash man page's Parameter Expansion section.
Or maybe with two consecutive awk calls:
ls -1 | awk -F- '{print $2}' | awk -F. '{print $1}'
How about
ls -l | awk {'print $9'} | grep -o -E '[0-9]*'
in the directory where the files reside?

Linux remove text from file

I want to write a command with removes an item from a file .todolist like that:
path="$HOME/.todolist"
if [ "$task" == "- " ];
then
exit 1
fi
cat $path | grep -v $1 > $path
When I cat $path | grep -v $1 all works perfect but when I try writing back to the file it leaves the file empty. What am I doing wrong?
As simple as that-
path="$HOME/.todolist"
grep -v $1 $path | sponge $path
This may be simpler:
sed -ie "/$1/d" $path
That will delete any line in the file containing the value in $1. The -i option tells sed to edit the file in place (not really, but it works as if it did). If $1 contains /s you'll get an error, though, but you can use other delimiters if you need to:
sed -ie "\%$1%d" $path
Note that with an alternate delimiter you must escape the first one with "\".
path="$HOME/.todolist"
if [ "$task" == "- " ];
then
exit 1
fi
a=$1
export a
perl -pi -e 'undef $_ if(/$ENV{a}/)' $path

How can I prepend a string to the beginning of each line in a file?

I have the following bash code which loops through a text file, line by line .. im trying to prefix the work 'prefix' to each line but instead am getting this error:
rob#laptop:~/Desktop$ ./appendToFile.sh stusers.txt kp
stusers.txt
kp
./appendToFile.sh: line 11: /bin/sed: Argument list too long
115000_210org#house.com,passw0rd
This is the bash script ..
#!/bin/bash
file=$1
string=$2
echo "$file"
echo "$string"
for line in `cat $file`
do
sed -e 's/^/prefix/' $line
echo "$line"
done < $file
What am i doing wrong here?
Update:
Performing head on file dumps all the lines onto a single line of the terminal, probably related?
rob#laptop:~/Desktop$ head stusers.txt
rob#laptop:~/Desktop$ ouse.com,passw0rd
a one-line awk command should do the trick also:
awk '{print "prefix" $0}' file
Concerning your original error:
./appendToFile.sh: line 11: /bin/sed: Argument list too long
The problem is with this line of code:
sed -e 's/^/prefix/' $line
$line in this context is file name that sed is running against. To correct your code you should fix this line as such:
echo $line | sed -e 's/^/prefix/'
(Also note that your original code should not have the < $file at the end.)
William Pursell addresses this issue correctly in both of his suggestions.
However, I believe you have correctly identified that there is an issue with your original text file. dos2unix will not correct this issue, as it only strips the carriage returns Windows sticks on the end of lines. (However, if you are attempting to read a Linux file in Windows, you would get a mammoth line with no returns.)
Assuming that it is not an issue with the end of line characters in your text file, William Pursell's, Andy Lester's, or nullrevolution's answers will work.
A variation on the while read... suggestion:
while read -r line; do echo "PREFIX " $line; done < $file
This could be run directly from the shell (no need for a batch / script file):
while read -r line; do echo "kp" $line; done < stusers.txt
The entire loop can be replaced by a single sed command that operates on the entire file:
sed -e 's/^/prefix/' $file
A Perl way to do it would be:
perl -p -e's/^/prefix' filename
or
perl -p -e'$_ = "prefix $_"' filename
In either case, that reads from filename and prints the prefixed lines to STDOUT.
If you add a -i flag, then Perl will modify the file in place. You can also specify multiple filenames and Perl will magically do all of them.
Instead of the for loop, it is more appropriate to use while read...:
while read -r line; do
do
echo "$line" | sed -e 's/^/prefix/'
done < $file
But you would be much better off with the simpler:
sed -e 's/^/prefix/' $file
Use sed. Just change the word prefix.
sed -e 's/^/prefix/' file.ext
If you want to save the output in another file
sed -e 's/^/prefix/' file.ext > file_new.ext
You don't need sed, just concatenate the strings in the echo command
while IFS= read -r line; do
echo "prefix$line"
done < filename
Your loop iterates over each word in the file:
for line in `cat file`; ...
sed -i '1a\
Your Text' file1 file2 file3
A solution without sed/awk and while loops:
xargs -n1 printf "$prefix%s\n" < "$file"

How to filter data out of tabulated stdout stream in Bash?

Here's what output looks like, basically:
? RESTRequestParamObj.cpp
? plugins/dupfields2/_DupFields.cpp
? plugins/dupfields2/_DupFields.h
I need to get the filenames from second column and pass them to rm. There's AWK script that goes like awk '{print $2}' but I was wondering if there's another solution.
If you have spaces between the ? and the filename then:
cut -c9-
If they're tabs then:
cut -f2
Placed your output in file
$> cat ./text
? RESTRequestParamObj.cpp
? plugins/dupfields2/_DupFields.cpp
? plugins/dupfields2/_DupFields.h
Edit it with sed
$> cat ./text | sed -r -e 's/(\?[\ \t]*)(.*)/\2/g'
RESTRequestParamObj.cpp
plugins/dupfields2/_DupFields.cpp
plugins/dupfields2/_DupFields.h
Sed in here is matching 2 parts of line -
? with tabs or spaces
Other characters until the end f the line
And then it changes whole line only with second part.
This might work for you:
echo "? RESTRequestParamObj.cpp" | sed -e 's/^\S\+/rm /' | sh
or using GNU sed
echo "? RESTRequestParamObj.cpp"| sed -r 's/^\S+/rm /e'
bash only solution, assuming your output comes from stdin:
while read line; do echo ${line##* }; done
use cut/perl instead
cut -f2 -t'\t'|xargs rm -rf
<your output>|perl -ne '#cols = split /\t/; print $cols[1]'|xargs rm -rf

Renaming a file by adding characters using sed

EX:
$ progaddtext file1 .txt<br>
should rename file1 to file1.txt
I found this code to successfully remove the text from the end of the first arg.
mv $1 $(echo $1 | sed "s/$2$//")
Just having a little trouble figuring out how to do the reverse.
If you have $1 as file1 and $2 as .txt why not just do:
mv "$1" "$1$2"
mv $1 $(echo $1 | sed "s/$/$2/")
Even though using mmv or rename would be much easier, and this question seems to lack a homework tag?
Try:
mv $1 $(echo $1 | sed -e "s/$/.txt/")

Resources