Shell Script split concatenate and re-use - bash

In Shell script I want to achieve something like below:
str="india,uk,us,uae"
I want to split it and concatenate each item as below and assign to some variable
newstr = '-myParam="india" -myParam="uk" -myParam="us" -myParam="uae"'
so that I can use above concatenated string in my next command as below
curl "admin/admin" "localhost" $newstr.
I found a way using local IFS and for loop but the variable updated inside loop is not retaining value outside of loop because it runs in a separate bash.

str="india,uk,us,uae"
var=-myparam=\"${str//,/\" -myparam=\"}\"
echo $var

Read the params into an array:
IFS=, read -a params <<< "$str"
And then loop through them and store the command in an array:
for i in "${params[#]}"; do
command+=(-myparam=\"$i\")
done
Now you can expand it using printf "${command[#]}":
$ printf "%s " "${command[#]}"
-myparam="india" -myparam="uk" -myparam="us" -myparam="uae"
That is, now you have to say:
curl "admin/admin" "localhost" "${command[#]}"
This is based on this answer by chepner: command line arguments fed from an array.

Below code would do :
$ str="india,uk,us,uae"
$ newstr=$(awk 'BEGIN{RS=","}{printf "-myParam=\"%s\" ",$1}' <<<"$str")
$ echo "$newstr"
-myParam="india" -myParam="uk" -myParam="us" -myParam="uae"
Also when you pass new string as parameter to curl, double quote it to prevent word splitting and globbing, so do :
curl "admin/admin" "localhost" "$newstr"
Note: <<< or herestring is only supported in a few shells (Bash, ksh, or zsh) if I recall correctly. If your shell does not support it use echo,pipe combination.

IFS=',' read -ra a <<< "${str//,/\",}";
curl "admin/admin" "localhost" "${a[#]/#/ -myParam=\"}\""
Explanation:
Starting with:
str="india,uk,us,uae";
Next, split the string into an array, using parameter substitution to insert " before each comma:
IFS=',' read -ra a <<< "${str//,/\",}";
Finally, we can get newstr through parameter substitution (while also appending the final "):
newstr="${a[#]/#/ -myParam=\"}\"";
newstr is now set to '-myParam="india" -myParam="uk" -myParam="us" -myParam="uae"'. We can skip the previous step and go straight to:
curl "admin/admin" "localhost" "${a[#]/#/ -myParam=\"}\""

Related

How to get first and second part of a string in bash on last occurrence of a delimiter

I need to split a string on the last occurrence of a delimiter and get both the parts into two variables.
Input could be
- stringOne_One/stringOne_Two/stingOne_Three
- stringTwo_One/stringTwo_Two
I want to split the string on the last occurrence of the delimiter "/" and get both the first and the last part of the string into two variables.
For the first example output should be
var1=stringOne_One/stringOne_Two
var2=stringOne_Three
For the second example, output should be
var1=stringTwo_One
var2=stringTwo_Two
How do I do this in bash. Would prefer a solution using AWK, but any other method is also acceptable.
Use dirname and basename like so:
my_var='stringOne_One/stringOne_Two/stingOne_Three'
var1=$(basename $my_var)
# stingOne_Three
var2=$(dirname $my_var)
# stringOne_One/stringOne_Two
With bash and a regex:
string='stringOne_One/stringOne_Two/stingOne_Three'
[[ "$string" =~ (.*)/(.*) ]]
var1="${BASH_REMATCH[1]}"
var2="${BASH_REMATCH[2]}"
Using parameter expansion:
$ x="stringOne_One/stringOne_Two/stingOne_Three"
$ var1="${x%/*}"
$ var2="${x##*/}"
$ echo "${var1} : ${var2}"
stringOne_One/stringOne_Two : stingOne_Three
$ x="stringTwo_One/stringTwo_Two"
$ var1="${x%/*}"
$ var2="${x##*/}"
$ echo "${var1} : ${var2}"
stringTwo_One : stringTwo_Two

How to avoid the read command cutting the user input which is a string by space

I wrote a bash script to read multiple inputs from the user
Here is the command:
read -a choice
In this way, I can put all the inputs in the choice variable as an array so that I can extract them using an index.
The problem is that when one of the inputs, which is a string has space in it, like
user1 google.com "login: myLogin\npassword: myPassword"
the read command will split the quoted string into 3 words. How can I stop this from happening?
bash doesn't process quotes in user input. The only thing I can think of is to use eval to execute an array assignment.
IFS= read -r input
eval "choice=($input)"
Unfortunately this is dangerous -- if the input contains executable code, it will be executed by eval.
You can use a tab instead of space as a field delimiter. For instance :
$ IFS=$'\t' read -a choice
value1 value2 a value with many words ## This is typed
$ echo ${choice[2]}
a value with many words
Regards!
Given risk of using eval, and the fact the input seems to have only two types of tokens: unquoted, and quoted, consider using scripting engine that will put all text into proper format that will be easy to read.
It's not clear from the example what other quoting rules are used. Example assume 'standard' escaped that can be processed with bash #E processor.
The following uses Perl one liner to generate TAB delimited tokens (hopefully, raw tabs can not be part of the input, but other character can be used instead).
input='user1 google.com "login: myLogin\npassword: myPassword"'
tsv_input=$(perl -e '$_ = " $ARGV[0]" ; print $2 // $3, "\t" while ( /\s+("([^"]*)"|(\S*))/g) ;' "$input")
IFS=$'\t' read -d '' id domain values <<< $(echo -e "${tsv_input#E}")
Or using a function to get more readable code
function data_to_tsv {
# Translate to TSV
local tsv_input=$(perl -e '$_ = " $ARGV[0]" ; print $2 // $3, "\t" while ( /\s+("([^"]*)"|(\S*))/g) ;' "$1")
# Process escapes
echo -n "${tsv_input#E}"
}
input='user1 google.com "login: myLogin\npassword: myPassword"'
IFS=$'\t' read -d '' id domain values <<< $(data_to_tsv "$input")

Adding a comma after $variable

I'm writing a for loop in bash to run a command and I need to add a comma after one of my variables. I can't seem to do this without an extra space added. When I move "," right next to $bams then it outputs *.sorted,
#!/bin/bash
bams=*.sorted
for i in $bams
do echo $bams ","
done;
Output should be this:
'file1.sorted','file2.sorted','file3.sorted'
The eventual end goal is to be able to insert a list of files into a --flag in the format above. Not sure how to do that either.
First, a literal answer (if your goal were to generate a string of the form 'foo','bar','baz', rather than to run a program with a command line equivalent to somecommand --flag='foo','bar','baz', which is quite different):
shopt -s nullglob # generate a null result if no matches exist
printf -v var "'%s'," *.sorted # put list of files, each w/ a comma, in var
echo "${var%,}" # echo contents of var, with last comma removed
Or, if you don't need the literal single quotes (and if you're passing your result to another program on its command line with the single quotes being syntactic rather than literal, you absolutely don't want them):
files=( *.sorted ) # put *.sorted in an array
IFS=, # set the comma character as the field separator
somecommand --flag "${files[*]}" # run your program with the comma-separated list
try this -
lst=$( echo *.sorted | sed 's/ /,/g' ) # stack filenames with commas
echo $lst
if you really need the single-ticks around each filename, then
lst="'$( echo *.sorted | sed "s/ /','/g" )'" # commas AND quotes
#!/bin/bash
bams=*.sorted
for i in $bams
do flag+="${flag:+,}'$i'"
done
echo $flag

Set bash variable equal to result of string where newlines are replaced by spaces

I have a variable equal to a string, which is a series of key/value pairs separated by newlines.
I want to then replace these newline characters with spaces, and set a new variable equal to the result
From various answers on the internet I've arrived at the following:
#test.txt has the content:
#test=example
#what=s0omething
vars="$(cat ./test.txt)"
formattedVars= $("$vars" | tr '\n' ' ')
echo "$taliskerEnvVars"
Problem is when I try to set formattedVars it tries to execute the second line:
script.sh: line 7: test=example
what=s0omething: command not found
I just want formattedVars to equal test=example what=s0omething
What trick am I missing?
Change your line to:
formattedVars=$(tr '\n' ' ' <<< "$secretsContent")
Notice the space of = in your code, which is not permitted in assignment statements.
I see that you are not setting secretsContent in your code, you are setting vars instead.
If possible, use an array to hold contents of the file:
readarray -t vars < ./test.txt # bash 4
or
# bash 3.x
declare -a vars
while IFS= read -r line; do
vars+=( "$line" )
done < ./test.txt
Then you can do what you need with the array. You can make your space-separated list with
formattedVars="${vars[*]}"
, but consider whether you need to. If the goal is to use them as a pre-command modifier, use, for instance,
"${vars[#]}" my_command arg1 arg2

Extracting multiple variables from a shell command in one line

I need to get some lines that a command returns to me. New example:
$ Return_Data
HOSTNAME:xpto.com.br
IP:255.255.255.0
DISKSPACE:1TB
LOCATION:argentina
I need only the LOCATION and IP lines and I need to gather that information in one single line. How should I proceed? I can use awk, shell, ksh, etc...
The cleanest solution is not, natively, a one-liner.
typeset -A data # Create an associative array.
while IFS=: read -r key value; do # Iterate over records, splitting at first :
data[$key]=$value # ...and assign each to that map
done < <(Return_Data) # ...with your command as input.
# ...and, to use the extracted values:
echo "Hostname is ${data[HOSTNAME]}; location is ${data[LOCATION]}"
That said, you can -- of course -- put all these lines together with ;s between them:
# extract content
typeset -A data; while IFS=: read -r key value; do data[$key]=$value; done < <(Return_Data)
# demonstrate its use
echo "Hostname is ${data[HOSTNAME]}; location is ${data[LOCATION]}"

Resources