Split string into array in shell script based on regex delimiter [duplicate] - bash

This question already has answers here:
Split a string only by spaces that are outside quotes
(4 answers)
Closed 2 years ago.
I have a string variable called JAVA_OPTS with various parameters in shell script.
-Dmaven.repo.local=/home/wangc/.m2/repository -Dtestparameter="some spaces" --add-exports=java.base/sun.nio.ch=ALL-UNNAMED
I'd like to split it into an array based on spaces, but not the space defined in escaped double quotes. For example I'd like to see an array with 3 elements:
-Dmaven.repo.local=/home/wangc/.m2/repository
-Dtestparameter="some spaces"
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED
I have tried
IFS=' ' read -r -a array <<< "$JAVA_OPTS"
But it can't tell the different space between double quotes, and return a four elements array as:
-Dmaven.repo.local=/home/wangc/.m2/repository
-Dtestparameter="some
spaces"
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED

Why do you require a regex solution? Getting the shell itself to parse this is significantly easier.
array=(-Dmaven.repo.local=/home/wangc/.m2/repository -Dtestparameter="some spaces" --add-exports=java.base/sun.nio.ch=ALL-UNNAMED)
Detouring the values via a string variable $JAVA_OPTS is precisely the wrong thing to do here, and makes the problem signicicantly harder.

Related

Convert string to an array in shell script [duplicate]

This question already has answers here:
Bash: Split string into character array
(20 answers)
Closed 4 months ago.
How can ı convert a string to an array in shell script?
For example i want to put "apple" to an array.
array[0] = a
array[1]=p
array[2]=p
array[3]=l
array[4]=e
I tried a lot of things but none of them worked. I tried to use IFS but i have no space or comma in my word so it didn't work.
Parameter expansion is relevant here: ${#var} gives you the number of characters in var, and ${var:start:len} takes len characters from var, starting at position start.
Combine those two techniques and you get:
#!/usr/bin/env bash
string='apple'
array=( )
for ((i=0; i<${#string}; i++)); do
array[$i]=${string:i:1}
done
declare -p array
...which emits as output:
declare -a array=([0]="a" [1]="p" [2]="p" [3]="l" [4]="e")

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.

Can I get the original quote characters surrounding arguments in my Bash script? [duplicate]

This question already has answers here:
How can I preserve quotes in printing a bash script's arguments
(7 answers)
Closed 4 years ago.
I have a script that logs the user argument list. This list is later processed by getopt.
If the script is started like:
./script.sh -a 'this is a sentence' -b 1
... and then I save "$#", I get:
-a this is a sentence -b 1
... without the single quotes. I think (because of the way Bash treats quotes) these are removed and are not available to the script.
For logging accuracy, I'd like to include the quotes too.
Can the original argument list be obtained without needing to quote-the-quotes?
No, there is no way to obtain the command line from before the shell performed whitespace tokenization, wildcard expansion, and quote removal on it.
If you want to pass in literal quotes, try
./script.sh '"-a"' '"this is a sentence"' '"-b"' '"1"'
Notice also how your original command line could have been written
'./script.sh' '-a' 'this is a sentence' '-b' '1'

How to print a variable which contains '$' in it in bash? [duplicate]

This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 7 years ago.
I'm writing a bash script which contains a variable called "line", and I want to print it's content.
The problem is that the "line" variable is a string which contains the '$' char.
My question is how can I print the value of the "line" variable, without replacing the dollars with variables.
For example, if "line" is containing "a$#gz%^", this code:
echo $line
Will output this:
a0gz%^
And if I'll put the '$line' in single quotes, it will just print '$line':
echo '$line'
$line
Hope you'll be able to help.
You have to quote the string when you assign it to the variable:
line='a$#gz%^'
Otherwise, $# is expanded before the assignment.
To output the literal variable, use double quotes
echo "$line"
It looks confusing at first, but it is actually pretty simple (at least to a first approximation):
string with $line in it -- never what you want, particularly if it includes a variable. OK if there is no variable and the string is just letters and numbers (and pattern characters if you want them to be expanded). Expands variables, splits into words, expands filename patterns.
"string with $line in it" -- expands variables, but doesn't word split or expand filename patterns
'string with $line in it' -- literal string, just the characters between the apostrophes
You can store string in variable having special characters by giving escape sequence like below -
line="a\$#gz%^"
And then echo $line

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