multiple substitutions on a string in bash [duplicate] - bash

This question already has answers here:
Can ${var} parameter expansion expressions be nested in bash?
(15 answers)
Closed 7 years ago.
I have a variable named inet which contains the following string:
inet="inetnum: 10.19.153.120 - 10.19.153.127"
I would like to convert this string to notation below:
10.19.153.120 10.19.153.127
I could easily achieve this with sed 's/^inetnum: *//;s/^ -//', but I would prefer more compact/elegant solution and use bash. Nested parameter expansion does not work either:
$ echo ${${inet//inetnum: /}// - / }
bash: ${${inet//inetnum: /}// - / }: bad substitution
$
Any other suggestions? Or should I use sed this time?

You can only do one substitution at a time, so you need to do it in two steps:
newinet=${inet/inetnum: /}
echo ${newinet/ - / }

Use a regular expression in bash as well:
[[ $inet =~ ([0-9].*)\ -\ ([0-9].*)$ ]] && newinet=${BASH_REMATCH[#]:1:2}
The regular expression could probably be more robust, but should capture the two IP addresses in your example string. The two captures groups are found at index 1 and 2, respectively, of the array parameter BASH_REMATCH and assigned to the parameter newinet.

Related

How to assign string outputs of expressions in variables without echo? [duplicate]

This question already has answers here:
How to pass the value of a variable to the standard input of a command?
(9 answers)
Closed 1 year ago.
I am currently saving string outputs from expressions like so
SOME_PATH="/some/path/file"
FILE_NAME=`echo "$SOME_PATH" | rev | cut -f 1 -d "/" | rev )`
FILE_FOLDER=`echo "$SOME_PATH" | sed s/$FILE_NAME//`
echo ${SOME_PATH}
echo ${FILE_NAME}
echo ${FILE_FOLDER}
which seems like the echo is superfluous, but I couldn't get it to work without it. What is the preferred way?
What is the preferred way?
The preferred way is to use variable expansions.
somepath='/some/path'
filename=${somepath##*/}
dirname=${somepath%/*}
Also: do not use backticks `, prefer $(...), quote variable expansions "s/$FILE_NAME//", prefer to use lower case variables for local variables and check your scripts with shellcheck.
How to assign string outputs of expressions in variables without echo?
Use here string to save one fork() call.
var=$(<<<"$var" command)

How to use parameter expansion correctly in bash [duplicate]

This question already has answers here:
Stripping prefixes and suffixes from shell words matching a pattern
(2 answers)
Difference between ${} and $() in Bash [duplicate]
(3 answers)
Closed 1 year ago.
I have a string with the structure task_name-student_name and I want to split it into two variables:
task: containing the chunk before the -
student: containing the chunk after the -
I can get this to work with sed:
string="task_name-student_name"
student=$(echo "$string" | sed "s/.*-//")
task=$(echo "$string" | sed "s/-[^-]*$//")
However, VS Code suggests "See if you can use $(variable//search/replace) instead".
So I have two questions:
Why would $(variable//search/replace) be better
How do I get the parameter expansion to work without it being interpreted as a command?
When I try
echo $("$string"//-[^-]*$//)
or
echo $(echo $("$string"//-[^-]*$//))
I get this output:
bash: task_name-student_name//-[^-]*$//: No such file or directory
Thanks in advance!
First: for variable expansion, you want curly braces instead of parentheses. $(something) will execute something as a command; ${something} will expand something as a variable. And just for completeness, $((something)) will evaluate something as an arithmetic expression (integers only, no floating point).
As for replacing the sed with a variable expansion: I wouldn't use $(variable//search/replace} for this; there are more appropriate modifications. ${variable#pattern} will remove the shortest possible match of pattern from the beginning of the variable's value, so use that with the pattern *- to remove through the first "-":
student=${string#*-}
Similarly, ${variable%pattern} will remove from the end of the variable's value, so you can use this with the pattern -* to remove from the dash to the end:
task=${string%-*}
Note that the patterns used here are "glob" expressions (like filename wildcards), not regular expressions like sed uses; they're just different enough to be confusing. Also, the way I've written these assumes there's exactly one "-" in the string; if there's a possibility some student will have a hyphenated name or something like that, you may need to modify them.
There are lots more modifications you can do in a parameter expansion; see the bash hacker's wiki on the subject. Some of these modifications will work in other shells besides bash; the # and % modifiers (and the "greedy" versions, ## and %%) will work in any shell that conforms to the POSIX standard.

Getting "command not found" while using cut on bash variable [duplicate]

This question already has answers here:
How to pass the value of a variable to the standard input of a command?
(9 answers)
Closed 4 years ago.
I have two variables in a bash script
hostname="ab78ascsoadp003.abc.com"
Loc=`$hostname | cut -c3,4`
I am getting an error ab78ascsoadp003.abc.com: command not found
I am trying to use cut command so that $Loc gets 78
While you can use cut to achieve this, sometimes it is useful to stick to bash:
hostname="ab78ascsoadp003.abc.com"
Loc=${hostname:3:2}
${parameter:offset:length} Substring Expansion. Expands to up to length characters of parameter starting at the character specified by offset. If length is omitted, expands to the substring of parameter starting at the character specified by offset. length and offset are arithmetic expressions <snip>
source: man bash
hostname="ab78ascsoadp003.abc.com"
Loc=$(cut -c3,4 <<<"$hostname")
you are missing an echo
Loc=`echo $hostname | cut -c3,4`

Setting a variable and utilizing sed [duplicate]

This question already has answers here:
Replace one substring for another string in shell script
(16 answers)
Closed 4 years ago.
I've been trying to wrap my head around this for over an hour now and my searches haven't helped yield the answer.
Trying to set a variable inside a bash script. This variable is taking variable-A and removing variable-B from it.
Prefix="$(echo ${Process} | sed -e 's/${Server}//g')"
So if Process=abcd1wxyz01 and Server=wxyz01, then Prefix should end up being abcd1.
I've tried so many iterations from online searches I honestly can't recall what all I've tried.
Your problem are the quotes, as pointed out in afsal_p's answer.
You could do this with parameter expansion instead:
$ process=abcd1wxyz01
$ server=wxyz01
$ prefix=${process%"$server"}
$ echo "$prefix"
abcd1
The ${word%suffix} expansion removes suffix from the end of word.
please use " instead of ' while using bash variables inside sed:
Prefix="$(echo ${Process} | sed -e "s/${Server}//g")"
echo $Prefix

Nested quotes in bash -- passing single argument containing spaces [duplicate]

This question already has answers here:
How to substitute quoted, multi-word strings as arguments?
(4 answers)
Closed 7 years ago.
script.sh:
#!/bin/bash
echo "First argument: $1"
wrapper.sh:
#!/bin/bash
CALLER='./script.sh "this should be one argument"'
$CALLER
what happens:
$ ./wrapper.sh
First argument: "this
what I was expecting:
$ ./wrapper.sh
First argument: this should be one argument
I tried different exercises to make it work the way I want it, but I can't find the way to invoke script.sh with single argument containing spaces from within wrapper.sh.
I would also like to understand the way nested quotes are interpreted.
This works instead (only last line changed):
#!/bin/bash
CALLER='./script.sh "this should be one argument"'
eval "$CALLER"
The reason for this is that quoting is applied at a different place in the parsing process than variable substitution, so you need to re-run the result of the substitution ($CALLER) through the parsing process (using eval), but quoted (the "…" around $CALLER) to avoid the field splitting that comes with the substitution already.
Further reading: the POSIX documentation on this, and the links already given in comments.

Resources