how to remove the extension of multiple files using cut in a shell script? - linux

I'm studying about how to use 'cut'.
#!/bin/bash
for file in *.c; do
name = `$file | cut -d'.' -f1`
gcc $file -o $name
done
What's wrong with the following code?

There are a number of problems on this line:
name = `$file | cut -d'.' -f1`
First, to assign a shell variable, there should be no whitespace around the assignment operator:
name=`$file | cut -d'.' -f1`
Secondly, you want to pass $file to cut as a string, but what you're actually doing is trying to run $file as if it were an executable program (which it may very well be, but that's beside the point). Instead, use echo or shell redirection to pass it:
name=`echo $file | cut -d. -f1`
Or:
name=`cut -d. -f1 <<< $file`
I would actually recommend that you approach it slightly differently. Your solution will break if you get a file like foo.bar.c. Instead, you can use shell expansion to strip off the trailing extension:
name=${file%.c}
Or you can use the basename utility:
name=`basename $file .c`

You should use the command substitution (https://www.gnu.org/software/bash/manual/bashref.html#Command-Substitution) to execute a command in a script.
With this the code will look like this
#!/bin/bash
for file in *.c; do
name=$(echo "$file" | cut -f 1 -d '.')
gcc $file -o $name
done
With the echo will send the $file to the standard output.
Then the pipe will trigger after the command.
The cut command with the . delimiter will split the file name and will keep the first part.
This is assigned to the name variable.
Hope this answer helps

Related

change name of file in nested folders

I have been trying to think of a way to rename file names that are listed in nested folders and am having an issue resolving this matter. as a test i have been able to cut out what part of the name i would like to alter but can't think of how to put that into a variable and chain the name together. the file format looks like this.
XXX_XXXX_YYYYYYYYYY_100426151653-all.mp3
i have been testing this format out to cut the part out i was looking to change but i am not sure this would be the best way of doing it.
echo XXX_XXXX_YYYYYYYYYY_100426095135-all.mp3 |awk -F_ '{print $4}' | cut -c 1-6
I would like to change the 100426151653 to this 20100426-151653 format in the name.
i have tried to use the rename the file with this command with this format 's/ //g' but that format did not work i had to resort to rename ' ' '' file name to remove a blank space.
so the file would start as this
XXX_XXXX_YYYYYYYYYY_100426151653-all.mp3
and end like this
XXX_XXXX_YYYYYYYYYY_20100426-151653-all.mp3
How about using find and a bash function
#!/bin/bash
modfn () {
suffix=$2
fn=$(basename $1)
path=$(dirname $1)
fld1=$(echo $fn | cut -d '_' -f1)
fld2=$(echo $fn | cut -d '_' -f2)
fld3=$(echo $fn | cut -d '_' -f3)
fld4=$(echo $fn | cut -d '_' -f4)
fld5=${fld4%$suffix}
l5=${#fld5}
fld6=${fld5:0:$(($l5 - 6))}
fld7=${fld5:$(($l5 - 6)):6}
newfn="${fld1}_${fld2}_${fld3}_20${fld6}-${fld7}${suffix}"
echo "moving ${path}/${fn} to ${path}/${newfn}"
mv ${path}/${fn} ${path}/${newfn}"
}
export -f modfn
suffix="-all.mp3"
export suffix
find . -type f -name "*${suffix}" ! -name "*-*${suffix}" -exec bash -c 'modfn "$0" ${suffix}' {} +
The above bash script uses find to search in the current folder and it's contents for files like WWW_XXXX_YYYYYYYYYY_AAAAAABBBBBB-all.mp3 yet excludes ones that are already renamed and look like WWW_XXXX_YYYYYYYYYY_20AAAAAA-BBBBBB-all.mp3.
W,X,Y,A,B can be any character other than underscore or dash.
All the found files are renamed
NOTE: There are ways to shrink the above script but doing that makes the operation less obvious.
This perl one-liner does the job:
find . -name "XXX_XXXX_YYYYYYYYYY_*-all.mp3" -printf '%P\n' 2>/dev/null | perl -nle '$o=$_; s/_[0-9]{6}/_20100426-/; $n=$_; rename($o,$n)if!-e$n'
Note: I came just with a find command and regex part. The credit for a perl one liner goes to perlmonks user at http://www.perlmonks.org/?node=823355

execute cut command inside bash script

Every line printed with the echo includes the forward slashes for the directories that the given files are in. I am trying to cut the forward slashes using the cut command but it is not working. The files are gzipped so they have the .gz extension.
#!/bin/bash
for filename in /data/logs/2017/month_01/201701*
do
echo $filename
cut $filename -d '/' -f1
done
Thanks in advance.
The order of commands is wrong. You need to stream the string input to the cut command via pipe(|) or here-strings(<<<).
echo "$filename" | cut -d '/' -f1
(or)
cut -d '/' -f1 <<<"$filename"
(or) using here-docs
cut -d '/' -f1 <<EOF
$filename
EOF
data
And don't forget to double-quote variables to avoid Word-Splitting done by the shell.
Assuming filename is /a/b/c.gz you just want c.gz ?
Well there's two very easy answers:
basename $filename
The other is:
echo ${filename##*/}
The latter make use bash's built-in string delete parameter expansion.
Another way of solving your problem, is you could change directory first, i.e.
#!/bin/bash
pushd /data/logs/2017/month_01
for filename in 201701*
do
echo $filename
done
popd
Reference:
http://wiki.bash-hackers.org/syntax/pe
(EDIT: Fixed typo identified by #123)
As suggested b #lnian cut command used with echo command via pipe sign
For getting only file name with your script you need to use.
cut with -f1 option will get first value before / which would give blank so you need to get last value from the filename.
#!/bin/bash
for filename in /data/logs/2017/month_01/201701*
do
echo "$filename" | rev| cut -d '/' -f1
done
rev command reverse the filename so you will get last value which is your filename

How to use awk's output on bash command line

I have a file named "01 - Welcome To The Jungle.mp3", and I want to do eyeD3 -t "Welcome To the Jungle" 01 - Welcome To The Jungle.mp3 to modify the tag of the all the files in the folder. I've extracted from the file with awk: "Welcome To The Jungle" doing:
#!/bin/bash
for i in *.mp3
do
eyeD3 -t $(echo ${i} | awk -F' - ' '{print $2}' | awk -F'.' '{print $1}') ${i}
done
It doesn't work. Neither the whole "$(echo S{i}....)" nor the "${i}" seem to work for replacing the names of the respective files.
You need to prevent word splitting on IFS (default: space, tab, newline) by shell, as your input filename contains space(s). The typical workaround is to use double quotes around the variable expansion.
Do:
for i in *.mp3; do eyeD3 -t "$(echo "$i")" | ...; done
You can leverage here string, <<<, to avoid the echo-ing:
for i in *.mp3; do eyeD3 -t <<<"$i" | ...; done
You need to double-quote variables that may contain spaces, as #heemayl already pointed out.
Also, in this example, instead of using awk,
it would be better to use native Bash pattern substitution to extract the title, for example:
for file in *.mp3; do
title=${file%.mp3}
title=${title#?????}
eyeD3 -t "$title" "$file"
done
That is:
Remove .mp3 at the end
Remove the first 5 characters (the count prefix NN -)

Need to cut part of a string in shell scripting

I have a string example.123.ytu.tar.gz
I want to have example.123.ytu.tar how can i get in shell scripting
I tried with
echo example.123.ytu.tar | cut -d "." -f3, But it is giving only tar
I would use basename for this.
$ basename --suffix ".gz" example.123.ytu.tar.gz
example.123.ytu.tar
You can find out more about it via man basename
echo example.123.ytu.tar.gz | cut -d "." -f1-4
example.123.ytu.tar
The -f option takes any comma separated list of fields and/or field ranges (with '-'). Eg
echo example.123.ytu.tar.gz | cut -d "." -f1,2,3,4
example.123.ytu.tar
gives the same output.
You could simply use grep
echo example.123.ytu.tar | grep -Eo '.*tar'
output: example.123.ytu.tar
The -E option enables extended regular expression mode and the -o option makes grep print only the part of the word that matched the regex.

How to store in a variable an echo | cut result?

for example
echo "filename.pdf" | cut -d'.' -f 1
This way I get the "filename" string.
I'd like to store it in a variable called FILE and then use it like this:
DIR=$PATH/$FILE.txt
So, my script wants to create a file.txt with the same name of the pdf (not a copy of the file, just the name)
This way I tried to assign the result of echo | cut
FILE=
but I get only "path/.txt" so the filename is missing.
FILE=$(echo "filename.pdf" | cut -d'.' -f 1)
So, my script wants to create a file.txt with the same name of the pdf
You can use BASH string manipulation:
s="filename.pdf"
p="${s/%.pdf/.txt}"
echo "$p"
filename.txt
POSIX parameter expansion would read
file=filename.pdf
filename="${file%%.*}" # Two % will remove multiple extensions, if applicable
dir=$path/$filename.txt

Resources