How to retain numbers in string in shell? - shell

I'm trying below
a = device.1.2
echo $a should print 1.2
Tried with sed 's/[a-z]//g' a

First thing first please make sure your shell variable doesn't have space while assigning value to it, so have it like this: a="device.1.2". With your shown samples, could you please try following once.
Have it with parameter substitution way: Where we need not to use an external program to get the value.
echo "${a#*.}"
OR with sed: Since OP was trying sed so adding one sed solution here, this nice command was given by Benjamin see comments for same.
echo "$a" | sed 's/^[^.]*\.//'

Related

How to use grep to print specific words only

I have a variable that contains a string-
$CCSR = "branches/features/arm_and_musl"
I want to pass only the "arm_and_musl" part to a variable, while excluding "branches/features", so something like this-
def dirname= sh " echo $CCSR | grep ????? "
But the main issue is that I don't want to explicitly mention "arm_and_musl" part, I want it to just exclude "branches/features" and print the remaining part whatever that may be.
I'm not sure what to put here so that only the part I want is passed to the variable.
Could you please suggest any solutions for this?
You could use something like this:
echo ${CCSR##*/}
to just output the needed section or if you need the variable to contain it use:
CCSR=${CCSR##*/}
Edit:
Since for some reason author was getting an error, thought i would include a solution with sed:
echo $CCSR | sed "s:.*/::"
Just use basename:
#!/bin/sh
CCSR="branches/features/arm_and_musl"
file=$(basename "$CCSR")
echo "$file"

Bash: how can I (1) read in a number from line "i" in a file that contains a column of numbers and (2) assign the value to a variable?

I have set up a sed expression that finds an old number in a file and replaces it with a new number. I have no problem with this.
I have many files. For each file, i, the new number needs to come from row i of a column of data in another file (let's called it "newNumbers"), like the example below.
1.2345
10.6789
100.101112
...
I can do this by doing (inside a for loop over file (i)):
i = 1
while read line
do
var[$i]="$line"
find ... # My sed expression for finding and replacing a word in file (i).
i=$((i+1))
done < newNumbers
However, this is not a good solution. "newNumbers" is so long that it will take days. I know the line I need from "newNumbers." It is line i, which corresponds to file i. So I want to read in the value from "newNumbers" at line i. I cannot get the syntax right to do this though (I am not experienced with bash). I'm using GNU sed on a Mac and have checked out several questions that seem related here. Examples that have resulted in "char1: missing command" or '"iq;d": command expects \ followed by text'-type errors are:
gsed -n -e "${i}" newNumbers
gsed 'iq;d' newNumbers
gsed "${i}q;d" newNumbers
I don't know if this is a Mac problem (GNU sed) or some syntax problem. Thank you for any help.
This is what worked but I have no idea why! I will post it, as there are probably other people who need to deal with this when working with input and output files.
Inside my for loop over file i, which starts at 0,
j=$((i+1))
newNumber_i=$(gsed "${j}q;d" newNumbers)
echo ${i%}
I needed the "echo" statement. I got it from ghostdog74's response here:
How to read output of sed into a variable

Match exact word in bash script, extract number from string

I'm trying to create a very simple bash script that will open new link base on the input command
Use case #1
$ ./myscript longname55445
It should take the number 55445 and then assign that to a variable which will later be use to open new link based on the given number.
Use case #2
$ ./myscript l55445
It should do the exact same thing as above by taking the number and then open the same link.
Use case #3
$ ./myscript 55445
If no prefix given then we just simply open that same link as a fallback.
So far this is what I have
#!/bin/sh
BASE_URL=http://api.domain.com
input=$1
command=${input:0:1}
if [ "$command" == "longname" ]; then
number=${input:1:${#input}}
url="$BASE_URL?id="$number
open $url
elseif [ "$command" == "l" ]; then
number=${input:1:${#input}}
url="$BASE_URL?id="$number
open $url
else
number=${input:1:${#input}}
url="$BASE_URL?id="$number
open $url
fi
But this will always fallback to the elseif there.
I'm using zsh at the moment.
input=$1
command=${input:0:1}
sets command to the first character of the first argument. It's not possible for a one character string to be equal to an eight-character string ("longname"), so the if condition must always fail.
Furthermore, both your elseif and your else clauses set
number=${input:1:${#input}}
Which you could have written more simply as
number=${input:1}
But in both cases, you're dropping the first character of input. Presumably in the else case, you wanted the entire first argument.
see whether this construct is helpful for your purpose:
#!/bin/bash
name="longname55445"
echo "${name##*[A-Za-z]}"
this assumes a letter adjacent to number.
The following is NOT another way to write the same, because it is wrong.
Please see comments below by mklement0, who noticed this. Mea culpa.
echo "${name##*[:letter:]}"
You have command=${input:0:1}
It takes the first single char, and you compare it to "longname", of course it will fail, and go to elseif.
The key problem is to check if the input is beginning with l or longnameor nothing. If in one of the 3 cases, take the trailing numbers.
One grep line could do it, you can just grep on input and get the returned text:
kent$ grep -Po '(?<=longname|l|^)\d+' <<<"l234"
234
kent$ grep -Po '(?<=longname|l|^)\d+' <<<"longname234"
234
kent$ grep -Po '(?<=longname|l|^)\d+' <<<"234"
234
kent$ grep -Po '(?<=longname|l|^)\d+' <<<"foobar234"
<we got nothing>
You can use regex matching in bash.
[[ $1 =~ [0-9]+ ]] && number=$BASH_REMATCH
You can also use regex matching in zsh.
[[ $1 =~ [0-9]+ ]] && number=$MATCH
Based on the OP's following clarification in a comment,
I'm only looking for the numbers [...] given in the input.
the solution can be simplified as follows:
#!/bin/bash
BASE_URL='http://api.domain.com'
# Strip all non-digits from the 1st argument to get the desired number.
number=$(tr -dC '[:digit:]' <<<"$1")
open "$BASE_URL?id=$number"
Note the use of a bash shebang, given the use of 'bashism' <<< (which could easily be restated in a POSIX-compliant manner).
Similarly, the OP's original code should use a bash shebang, too, due to use of non-POSIX substring extraction syntax.
However, judging by the use of open to open a URL, the OP appears to be on OSX, where sh is essentially bash (though invocation as sh does change behavior), so it'll still work there. Generally, though, it's safer to be explicit about the required shell.

Is there a way to do multiple shell variable expansions/parameter substitutions?

I have a line in a script that works in zsh but does not work in bash:
SHORTDIR=${${${PWD##*/}//./_dot_}//:/_colon_}
This is basically a short/efficient version of basename $PWD | sed -e 's/\./0/g' -e 's/:/1/g'.
What's the syntax for stringing together variable expansions?
Sadly, the first part of the substitution has to be a parameter name. An alternative sed version would be:
echo $PWD | sed -e 's!.*/!!' -e 'y/.:/01/'
I was hoping that there'd be a better way than
SHORTDIR=${PWD##*/}
SHORTDIR=${SHORTDIR//./_dot_}
SHORTDIR=${SHORTDIR//:/_colon_}
but this is what I'm sticking to.
According to the answers to the question linked by #perreal, bash basically does not allow for expanded variables themselves as a "parameter" and that's why it fails.
Just to throw this out there, many people don't know that multiple assignments can be done in one line. E.g.:
$ a=1234 a=${a:0:3} a=${a/1}
or
SHORTDIR=${PWD##*/} SHORTDIR=${SHORTDIR//./_dot_} SHORTDIR=${SHORTDIR//:/_colon_}

Search and replace with sed by both in pattern and line

I went through lots of similar posts but none could be applied to mine.
I would like to search and replace using sed in some particular lines in a way that in only matches the first occurrence; lets say I have this part of the script:
processor <- read.table("../mall_all/adpcm/FULL_DB-constprop", header=TRUE, colClasses=c("reassociate"="factor", "scalarrepl"="factor", "inline"="factor", "sccp"="factor", "loop_reduce"="factor"))
processor<-processor[-c(20:40)]
processor$intensity <- processor$int_high - processor$int_low
processor$performance<- processor$perf_high - processor$perf_low
processor<-processor[-c(1:4)]
processor<-processor[,!names(processor) %in% c("constprop")]
I want to keep changing the $constprop variable in
"../mall_all/adpcm/FULL_DB-constprop"
AND
[,!names(processor) %in% c("constprop")]
in a loop that I wrote, the problem is; I want the colClasses parameteres AND the rest of the scripts remains the same while entering the loop (the loop has the compiler options like: reassociate, inline, constprop, etc)
I was wondering why my search and replace didn't work :
set -x
compilerOptionList="constprop dce inline instcombine licm loop_reduce loop_rotate loop_unroll loop_unswitch loop_unswitch mem2reg memcpyopt reassociate scalarrepl sccp simplifycfg "
stringToBeReplaced=constprop
for compilerOption in $compilerOptionList
do
echo "Using compiler option: $compilerOption"
//here you could see the sed scripts
sed -i "1,15 /FULL_DB/,/header/ s/$stringToBeReplaced/$compilerOption/" r.scr
stringToBeReplaced=$compilerOption
make
mv Rplots.pdf Rplots_adpcm_$compilerOption.pdf
echo "DONE! $compilerOption"
done
Thanks all for your time and help ;)
Amir
I'm not sure having rightly understood your need, but maybe someting like
sed -e "
1,15ba;
/FULL_DB/,/header/ba;
bb;
:a;
s/stringToBeReplaced/$compilerOption/;
:b;
" -i r.scr
could do the job.
This line is problematic
sed -i "1,15 /FULL_DB/,/header/ s/$stringToBeReplaced/$compilerOption/" r.scr
It's not a valid sed command syntax. You'll need to enclose part of it in braces like this
sed -i "1,15 { /FULL_DB/,/header/ s/$stringToBeReplaced/$compilerOption/ }" r.scr
But I think a tidier way is to use separate files for input and output of sed, i.e. change that line to
sed "1,15 s/constprop/$compilerOption/" r.scr_tmp >r.scr
You don't need the stringToBeReplaced variable. This way you always substitute "constprop", and don't have to worry that the string to be replaced appears elsewhere in the code.
r.scr_tmp would contain the same code as r.scr except that the constprop part of r.scr_tmpremains unchanged.

Resources