This question already has answers here:
How can I look up a variable by name with #!/bin/sh (POSIX sh)?
(4 answers)
Bash String concatenation and get content
(2 answers)
Closed 4 years ago.
I've got about a day of experience in bash as of now..
string () {
for (( i=0; i<${#1}; i++ ))
do
echo "$"${1:$i:1}""
done
}
string "hello"
This script returns "$h", "$e", "$l", "$l", "$o",
but I actually want it to return the contents of variables h, e, l, l and o.
How do I do that?
You need to use indirect parameter expansion:
for ((i=0; i<${#1}; i++)); do
t=${1:i:1}
echo "${!t}"
done
${!t} takes the value of $t, and treats that as the name of the parameter to expand.
A one-liner using eval to safely write a series of echos to output bash parameter transformation assignment statements, with GNU grep divvying up the input string:
h=foo o=bar
string() { eval $(printf 'echo ${%s#A};\n' $(grep -o . <<< "$#" )) ; }
string hello
Output, (blank lines represent the unset variables $e and $l):
h='foo'
o='bar'
Related
This question already has answers here:
How do I split a string on a delimiter in Bash?
(37 answers)
Closed 1 year ago.
Let's say I have this string:
NAMES="Mike&George&Norma"
IFS=$'&'
for NAME in $NAMES
do
echo ${NAME}
done
So I can loop through the NAMES.
But what if I only need George, i.e. the name at index 1?
How can I get NAMES[1]?
If mapfile aka readarray is available/acceptable.
#!/usr/bin/env bash
names="Mike&George&Norma"
mapfile -td '&' name <<< "$names"
printf '%s\n' "${name[#]}"
Prints all elements/strings in between the &, so
printf '%s\n' "${name[0]}"
printf '%s\n' "${name[1]}"
printf '%s\n' "${name[2]}"
Should print them names one by one.
See the builtin section of the bash manual https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html
$ NAMES="Mike&George&Norma";
$ echo "$NAMES" | cut -d'&' -f2
George
field counting starts with 1, unlike array indexing.
Using OP's current code one idea would be to add a counter to the loop processing, eg:
NAMES="Mike&George&Norma"
loop_ctr=-1
match_ctr=1
origIFS="${IFS}" # save current IFS
IFS=$'&'
for NAME in $NAMES
do
((loop_ctr++))
[[ "${loop_ctr}" -ne "${match_ctr}" ]] && # if loop_ctr != match_ctr then skip to next pass through loop
continue
echo ${NAME}
done
IFS="${origIFS}" # reset to original IFS
This generates as output:
George
NOTE: My preference would be to parse the string into an array (via mapfile/readarray) ... and #jetchisel beat me to that idea :-)
This question already has answers here:
Bash - variable variables [duplicate]
(4 answers)
Indirect variable assignment in bash
(7 answers)
Closed 1 year ago.
How can I achieve casing text like this:
string="this is a string"
for case in u l c
do
declare -"${case}" out
out=$string
echo $out
done
#THIS IS A STRING
#this is a string
#This is a string
with looping through the names of declared variables:
declare -u UPPER
declare -l LOWER
declare -c CAPITALIZE
for i in UPPER LOWER CAPITALIZE
do
i=$string
echo $i
done
#this is a string
#this is a string
#this is a string
(note all lower case)
You may use it like this:
string="this is a string"
declare -u UPPER
declare -l LOWER
declare -c CAPITALIZE
for i in UPPER LOWER CAPITALIZE; do
declare $i="$string" # assign value to each var
echo "$i='${!i}'" # print each var
done
Output:
UPPER='THIS IS A STRING'
LOWER='this is a string'
CAPITALIZE='This is a string'
Use a nameref:
for i in UPPER LOWER CAPITALIZE; do
declare -n var=$i # variable `var` is a ref to variable named in $i
var=$string
echo "$var"
done
THIS IS A STRING
this is a string
This is a string
I'd do something like this, with a function to return its argument with a new case:
#!/usr/bin/env bash
function recase() {
case "$1" in
UPPER) local -u str="$2";;
LOWER) local -l str="$2";;
CAPITALIZE) local -c str="$2";;
esac
printf "%s\n" "$str"
}
string="this is a string"
for c in UPPER LOWER CAPITALIZE
do
recase "$c" "$string"
done
This question already has answers here:
Passing arguments by reference
(9 answers)
Closed 2 years ago.
I have a function myFunction() that shall take an integer variable from outside, print it and then increment it.
This works:
myFunction:
myFunction() {
local var="${1}"
eval "printf '%s\n' \$$var"
eval "$var=$(($var+1))"
}
But, I don't want to use eval in this as a user of this function might enter a wrong variable name that might then be executed. I would like to use something like printf -v as it would make the usage safer.
How can I do this?
You can (only?) do this without eval if you are happy enumerating all possible variable names.
myFunction () {
case $1 in
(frobme) printf '%s\n' $frobme; : $((++frobme));;
(zapme) printf '%s\n' $zapme; : $((++zapme));;
(*) printf 'invalid name: %s\n' "$1" >&2;;
esac
}
This question already has answers here:
Integer ASCII value to character in BASH using printf
(13 answers)
Closed 3 years ago.
I have a binary "crackme" which i want to try all ASCII characters as parameters, here's what i've done so far.
#!/bin/bash
for ((i=32;i<127;i++))
do
c="\\$(printf %03o "$i")";
echo $c;
./crackme $c;
done
The command executed is "./crackme \65" and obviously i'm trying to execute "./crackme A".
For posterity, a couple of useful functions:
# 65 -> A
chr() { printf "\\x$(printf "%x" "$1")"; }
# A -> 65
ord() { printf "%d" "'$1"; }
The odd final parameter of the ord printf command is documented:
Arguments to non-string format specifiers are treated as C language constants, except that a leading plus or minus sign is allowed, and if the leading character is a single or double quote, the value is the ASCII value of the following character.
then
for ((i = 32; i < 127; i++)); do
./crackme "$(chr $i)"
done
Not pretty, but this works:
for ((i=32;i<127;i++))
do
printf -v c '\\x%x' "$i"
./crackme "$(echo -e $c)"
done
This question already has answers here:
When to wrap quotes around a shell variable?
(5 answers)
Closed 1 year ago.
Why in this case doesnt generate new lines in Bash:
#!/bin/bash
function sample() {
local DATA=""
DATA="test1"$'\n'
DATA="${DATA}test2"$'\n'
echo ${DATA}
}
DATA=$(sample)
printf "%s" "${DATA}"
$DATA is expanded, and all whitespace (including newlines) are used for word-splitting, before echo ever runs. You should always quote parameters expansions.
sample() {
local DATA=""
DATA="test1"$'\n'
DATA="${DATA}test2"$'\n'
echo "${DATA}"
}
You must use the -e option of echo for it to interpret the \n character:
echo -e "${DATA}"