How do prevent whitespace from appearing in these bash variables? - bash

I'm reading in values from an .ini file, and sometimes may get trailing or leading whitespace.
How do I amend this first line to prevent that?
db=$(sed -n 's/.*DB_USERNAME *= *\([^ ]*.*\)/\1/p' < config.ini);
echo -"$db"-
Result;
-myinivar -
I need;
-myinivar-

Use parameter expansion.
echo "=${db% }="

You don't need the .* inside the capturing group (or the semicolon at the end of line):
db="$(sed -n 's/.*DB_USERNAME *= *\([^ ]*\).*/\1/p' < config.ini)"
To elaborate:
.* matches anything at all
DB_USERNAME matches that literal string
* (a single space followed by an asterisk) matches any number of spaces
= matches that literal string
* (a single space followed by an asterisk) matches any number of spaces
\( starts the capturing group that is used for \1 later
[^ ] matches anything which is not a space character
* repeats that zero or more times
\) ends the capturing group
.* matches anything at all
Therefore, the result will be all the characters after DB_USERNAME = and any number of spaces, up to the next space or end of line, whichever comes first.

You can use echo to trim whitespace:
db='myinivar '
echo -"$(echo $db)"-
-myinivar-

Use crudini which handles these ini file edge cases transparently
db=$(crudini --get config.ini '' DB_USERNAME)

To get rid of more than one trailing space, use %% which removes the longest matching pattern from the end of the string
echo "=${db%% *}="

Related

Build a variable made with 2 sub-stings of another variable in bash

Here is a script I use:
for dir in $(find . -type d -name "single_copy_busco_sequences"); do
sppname=$(dirname $(dirname $(dirname $dir))| sed 's#./##g');
for file in ${dir}/*.faa; do name=$(basename $file); cp $file /Users/admin/Documents/busco_aa/${sppname}_${name}; sed -i '' 's#>#>'${sppname}'|#g' /Users/admin/Documents/busco_aa/${sppname}_${name}; cut -f 1 -d ":" /Users/admin/Documents/busco_aa/${sppname}_${name} > /Users/admin/Documents/busco_aa/${sppname}_${name}.1;
done;
done
The sppname variable is something like Gender_species
do you know how could I add a line in my script to creat a new variable called abbrev which transformes Gender_species into Genspe, the 3 first letters cat with the 3 first letters after _
exemples:
Homo_sapiens gives Homsap
Canis_lupus gives Canlup
etc
Thank for your help :)
You can achieve this using a regular expression with sed:
echo "Homo_sapiens" | sed -e s'/^\(...\).*_\(...\).*/\1\2/'
Homsap
start, get 3 chars (to keep in \1), anything, _, anything, get 3 chars (to keep in \2), anything
Replace echo "Homo_sapiens" by your $dir thing
PS: will fail if you have less than 3 chars in one word
You can do it all with bash built-in parameter expansions. Specifically, string indexes and substring removal.
$ a=Homo_sapiens; prefix=${a:0:3}; a=${a#*_}; postfix=${a:0:3}; echo $prefix$postfix
Homsap
$ a=Canis_lupus; prefix=${a:0:3}; a=${a#*_}; postfix=${a:0:3}; echo $prefix$postfix
Canlup
Using bash built-ins is always more efficient than spawning separate subshell(s) to invoke utilities to accomplish the same thing.
Explanation
Your string index form (bash only) allows you to index characters from within a string, e.g.
* ${parameter:offset:length} ## indexes are zero based, ${a:0:2} is 1st 2 chars
Where parameter is simply the variable name holding the string.
(you can index from the end of a string by using a negative offset preceded by a space or enclosed in parenthesis, e.g. a=12345; echo ${a: -3:2} outputs "34")
prefix=${a:0:3} ## save the first 3 characters in prefix
a=${a#*_} ## remove the front of the string through '_' (see below)
postfix=${a:0:3} ## save the first 3 characters after '_'
Your substring removal forms (POSIX) are:
${parameter#word} trim to 1st occurrence of word from parameter from left
${parameter##word} trim to last occurrence of word from parameter from left
and
${parameter%word} trim to 1st occurrence of word from parameter from right
${parameter%%word} trim to last occurrence of word from parameter from right
(word can contain globbing to expand to a pattern as well)
a=${a#*_} ## trim from left up to (and including) the first '_'
See bash(1) - Linux manual page for full details.

adding a colon after every two letters in an alphanumeric string in shell

So i have an alphanumeric string 10006cc2190ab011 i am trying to add a colon after every two letters in this alphanumeric string.
this is the string : 10006cc2190ab011
i want it be - 10:00:6c:c2:19:0a:b0:11
Thanks in advance.
A sed solution:
$ echo 10006cc2190ab011 | sed 's/../&:/g; s/:$//'
10:00:6c:c2:19:0a:b0:11
Replaces each non-overlapping pair of characters with the same pair plus :. In the end removes the trailing : (if input text had even length).
str=10006cc2190ab011; str="${str//??/${.sh.match}:}"; echo ${str%:}
is doing the same replacement without the use of an external command, just using ksh-internals.
Doing the same as in sed (the other answer). Replace in $str every // two charactes ?? with / the matched string and a : (every match is kept in the ksh-variable ${.sh.match}). Then print $str without the last % ':'.

BASH - Capture string between a FIXED and 2 possible variables

To get what is between "aa=" and either % or empty
string = "aa=value%bb"
string2 = "bb=%aa=value"
The rule must work on both strings to get the value of "aa="
I would like a BASH LANGUAGE solution if possible.
Use this:
result=$(echo "$string" | grep -o 'aa=[^%]*')
result=${result:3} # remove aa=
[^%]* matches any sequence of characters that doesn't contain %, so it will stop when it gets to % or the end of the string. $(result:3} expands to the substring starting from character 3, which removes aa= from the beginning.

trying to understand nested brackets in sed script

/^Host.*latency.*/{
$!N
/MAC Address/{
s/.*(\(.*\)) .*MAC Address: \(.*\) .*/\1 -> \2/
}
}
/[Nn]map/d
s/^Host .*is up/& but MAC Address cannot be found/
I am trying to understand sed script as above.Can some one help me to understand I never used sed as above.
Its use is
nmap -sP 192.168.1.0/20 | sed -f sedcript.sh
If you mean the nested parentheses in (\(.*\)). The outer pair are literal and the inner, escaped pair capture the string matched by the enclosed regular expression. The backreference \1 outputs this captured string. The \2 backreference outputs the string captured by the second pair of escaped parentheses.
If you mean the curly braces, they surround blocks of commands. The outer group says that if the line matches ^Host.*latency.* then execute the enclosed command. The $!N command appends the next line of the file if the current line isn't the last. If the combination of the lines matches MAC Address then the block inside the next pair of curly braces is executed (the substitution is performed).
You can read it like this:
/^Host.*latency.*/{ - If the line matches this regex, then
$!N - Append the next line if the current line isn't the last line
/MAC Address/{ - If the combined lines match this regex, then
s/.*(\(.*\)) .*MAC Address: \(.*\) .*/\1 -> \2/ - Make this substitution
} - End if
} - End if
/[Nn]map/d - If the pattern space (combined lines) matches this, then delete it
s/^Host .*is up/& but MAC Address cannot be found/ - Make this substitution

pattern matching in ruby

cud any body tell me how this expression works
output = "#{output.gsub(/grep .*$/,'')}"
before that opearation value of ouptput is
"df -h | grep /mnt/nand\r\n/dev/mtdblock4 248.5M 130.7M 117.8M 53% /mnt/nand\r\n"
but after opeartion it comes
"df -h | \n/dev/mtdblock4 248.5M 248.5M 130.7M 117.8M 53% /mnt/nand\r\n "
plzz help me
Your expression is equivalent to:
output.gsub!(/grep .*$/,'')
which is much easier to read.
The . in the regular expression matches all characters except newline by default. So, in the string provided, it matches "grep /mnt/nand", and will substitute a blank string for that. The result is the provided string, without the matched substring.
Here is a simpler example:
"hello\n\n\nworld".gsub(/hello.*$/,'') => "\n\n\nworld"
In both your provided regex, and the example above, the $ is not necessary. It is used as an anchor to match the end of a line, but since the pattern immediately before it (.*) matches everything up to a newline, it is redundant (but does not cause harm).
Since gsub returns a string, your first line is exactly the same as
output = output.gsub(/grep .*$/, '')
which takes the string and removes any occurance of the regexp pattern
/grep .*$/
i.e. all parts of the string that start with 'grep ' until the end of the string or a line break.
There's a good regexp tester/reference here. This one matches the word "grep", then a space, then any number of characters until the next line-break (\r or \n). "." by itself means any character, and ".*" together means any number of them, as many as possible. "$" means the end of a line.
For the '$', see here http://www.regular-expressions.info/reference.html
".*$" means "take every character from the end of the string" ; but the parser will interpret the "\n" as the end of a line, so it stops here.

Resources