Bash add characters before and after $foo - bash

So if I have
$foo = foo
I would like to add : at the beginning and ! at the end. I tried the below:
bar=$( ":" $foo "!" )

You can't use bar=$( ":" $foo "!" ), with this command you try to assign the result of :foo! command to your variable. You will probably get an output like :foo!: command not found and your $bar variable will be not set.
You can use :
foo=foo
bar=':'$foo'!'
echo $bar
# Will return :foo!

the builtin printf can do that also but I'm not sure if it is portable solution.
foo=foo
printf -v bar ":$foo!"
echo "$bar"
see
help printf
or
man printf

Related

How to remove the character before the pattern found? (Unix)

I have a variable:
$var="-- ---comment- --
abcd;"
I want to remove every character that is between "--" comment "--"
Expected output:
$var="abcd;"
What I am trying in test.sh
#!/bin/bash
var="----comment---
abcd;"
test=$(sed 's/^--.*--/' $var)
echo $test
It is not working. I get the following error:
command not found
Trying to replace the pattern that you don't expect in output with nothing, something like this
test=$(echo $var | sed 's/^--.*--//g')
Should work.
In bash:
$ cat foo.sh
var="----comment---
abcd;"
echo "$var" # this outputs the original var
echo "${var/--* /}" # this output replacing everything between -- and " "
$ bash foo.sh
----comment---
abcd;
abcd;
You can set the output to a variable by
$ var="${var/--* /}"

How to print literal string "$1" in bash script?

I want to print string called "$1". But when I do this with echo it prints string which equals to "$1" variable. How can I print "$1" just like string?
for example:
set -- "output" # this sets $1 to be "output"
echo $1 # ==> output
But I want this:
echo $1 # ==> $1
You have to escape the $ to have it shown:
$ echo "\$1"
or, as noted by JeremyP in comments, just use single quotes so that the value of $1 does not get expanded:
$ echo '$1'
You need to either:
Enclose the variable in SINGLE quotes: echo '$1'
Escape the $ sign: echo "\$1"

BASH: Substituting a variable inside a variable during echo

I explained my question in the comments:
VAR=
INS="Installing $VAR"
echo $INS
. # In each echo command I want to dynamically substitute
. # the $VAR variable in the $INS variable. I want to do
echo $INS # the substitution of the variable on echo command.
Is this possible?
You need a function to do the job gracefully.
say() {
echo "Installing $INS"
}
INS=hello
say
INS=world
say
Or just this:
say() {
echo "Installing $#"
}
say hello
say world
For example:
[ghoti#pc ~]$ cat varins
#!/bin/bash
msg='Installing "$VAR"'
for VAR in foo bar baz; do
eval echo "$msg"
done
[ghoti#pc ~]$ ./varins
Installing foo
Installing bar
Installing baz
[ghoti#pc ~]$
This relies on the fact that $VAR won't be expanded inside single quotes. The eval command will expand the $msg variable, in which the shell will find $VAR to replace.
Parameter substitution can do it also:
ins='aaa $var aaa'
var='xxx'
echo "'${ins//\$var/$var}'"
result:
'aaa xxx aaa'
INS='Installing $VAR'
result=`eval "echo $INS"`
echo $result
you have to use single quotes to not substitute $VAR on creation of INS
eval evaluates $INS at runtime and with echo and backticks it is returned as substituted string
As Hachi said, you need single quotes to prevent $VAR from premature evaluation. Graham suggests in the comments to avoid the subshell call like this:
#!/bin/bash
VAR=17
INS='Installing $VAR'
eval "echo \"$INS\""
VAR=42
eval "echo \"$INS\""
If you don't do it:
VAR=23
INS="Installing $VAR"
echo $(eval "echo $INS")
VAR=8
echo $(eval "echo $INS")
23 is bound immediately, and the assignment VAR=8 isn't noticed.
Result:
Installing 17
Installing 42
Installing 23
Installing 23

assinging "-n" string to a variable doesn't work

$ OPTION="-n"
$ echo $OPTION
$
Nothing happens. I expected this.
$ OPTION="-n"
$ echo $OPTION
-n
$
Why is this?
-n is a parameter to echo, which means the trailing newline is suppressed. The fact that there's no empty line between $ echo $OPTION and the following $ means that $OPTION is properly set to -n.
If you put something else in front of $OPTION, the echo will work as you expect it to. echo only interprets words at the beginning of the command as options. As soon as it finds a non-option word ("OPTION", in this case), all words that follow are treated as literals, and not parsed as options to echo.
$ echo OPTION is set to $OPTION
OPTION is set to -n
$
Remember that the shell expands environment variables before the command is executed. Thus:
option="-n"
echo $option
becomes
echo -n ""
With the value of $option being interpreted as a parameter for the echo command. If you were using Kornshell (which is 95% similar to BASH), you could have used the builtin print command instead:
option="-n"
print -- "$option"
Unfortunately, BASH doesn't have the print command, and using the double dash in the BASH echo command will print out a double dash -- not what you want.
Instead, you'll have to use the printf command which is a bit slower than echo:
option="-n"
printf -- "$option\n" #Must include the \n to make a new line!
Of course, if you had this, you'd be in trouble:
option="%d"
printf -- "$option\n"
To get around that:
option="%d"
printf "%s\n", "$option"
By the way, you have the same problems with test:
option="-n"
if [ "$option" -eq "-n" ] #Won't work!
This is why you'll see people do this:
if [ "x$option" -eq "x-n" ] #Will work
To get the desired result, you could do this:
$ OUTPUT='-n'
$ echo -en ${OUTPUT}\\n

Indirect parameter substitution in shell script

I'm having a problem with a shell script (POSIX shell under HP-UX, FWIW). I have a function called print_arg into which I'm passing the name of a parameter as $1. Given the name of the parameter, I then want to print the name and the value of that parameter. However, I keep getting an error. Here's an example of what I'm trying to do:
#!/usr/bin/sh
function print_arg
{
# $1 holds the name of the argument to be shown
arg=$1
# The following line errors off with
# ./test_print.sh[9]: argval=${"$arg"}: The specified substitution is not valid for this command.
argval=${"$arg"}
if [[ $argval != '' ]] ; then
printf "ftp_func: $arg='$argval'\n"
fi
}
COMMAND="XYZ"
print_arg "COMMAND"
I've tried re-writing the offending line every way I can think of. I've consulted the local oracles. I've checked the online "BASH Scripting Guide". And I sharpened up the ol' wavy-bladed knife and scrubbed the altar until it gleamed, but then I discovered that our local supply of virgins has been cut down to, like, nothin'. Drat!
Any advice regarding how to get the value of a parameter whose name is passed into a function as a parameter will be received appreciatively.
You could use eval, though using direct indirection as suggested by SiegeX is probably nicer if you can use bash.
#!/bin/sh
foo=bar
print_arg () {
arg=$1
eval argval=\"\$$arg\"
echo "$argval"
}
print_arg foo
In bash (but not in other sh implementations), indirection is done by: ${!arg}
Input
foo=bar
bar=baz
echo $foo
echo ${!foo}
Output
bar
baz
This worked surprisingly well:
#!/bin/sh
foo=bar
print_arg () {
local line name value
set | \
while read line; do
name=${line%=*} value=${line#*=\'}
if [ "$name" = "$1" ]; then
echo ${value%\'}
fi
done
}
print_arg foo
It has all the POSIX clunkiness, in Bash would be much sorter, but then again, you won't need it because you have ${!}. This -in case it proves solid- would have the advantage of using only builtins and no eval. If I were to construct this function using an external command, it would have to be sed. Would obviate the need for the read loop and the substitutions. Mind that asking for indirections in POSIX without eval, has to be paid with clunkiness! So don't beat me!
Even though the answer's already accepted, here's another method for those who need to preserve newlines and special characters like Escape ( \033 ): Storing the variable in base64.
You need: bc, wc, echo, tail, tr, uuencode, uudecode
Example
#!/bin/sh
#====== Definition =======#
varA="a
b
c"
# uuencode the variable
varB="`echo "$varA" | uuencode -m -`"
# Skip the first line of the uuencode output.
varB="`NUM=\`(echo "$varB"|wc -l|tr -d "\n"; echo -1)|bc \`; echo "$varB" | tail -n $NUM)`"
#====== Access =======#
namevar1=varB
namevar2=varA
echo simple eval:
eval "echo \$$namevar2"
echo simple echo:
echo $varB
echo precise echo:
echo "$varB"
echo echo of base64
eval "echo \$$namevar1"
echo echo of base64 - with updated newlines
eval "echo \$$namevar1 | tr ' ' '\n'"
echo echo of un-based, using sh instead of eval (but could be made with eval, too)
export $namevar1
sh -c "(echo 'begin-base64 644 -'; echo \$$namevar1 | tr ' ' '\n' )|uudecode"
Result
simple eval:
a b c
simple echo:
YQpiCmMK ====
precise echo:
YQpiCmMK
====
echo of base64
YQpiCmMK ====
echo of base64 - with updated newlines
YQpiCmMK
====
echo of un-based, using sh instead of eval (but could be made with eval, too)
a
b
c
Alternative
You also could use the set command and parse it's output; with that, you don't need to treat the variable in a special way before it's accessed.
A safer solution with eval:
v=1
valid_var_name='[[:alpha:]_][[:alnum:]_]*$'
print_arg() {
local arg=$1
if ! expr "$arg" : "$valid_var_name" >/dev/null; then
echo "$0: invalid variable name ($arg)" >&2
exit 1
fi
local argval
eval argval=\$$arg
echo "$argval"
}
print_arg v
print_arg 'v; echo test'
Inspired by the following answer.

Resources