I have to declare a string composed of different variables at the starting of a loop in order to print it later just with eval $command >> file.txt avoiding retype every time the string $command itself. But my $command string is composed of other variables and I need to be able to update them before printing. Here a brief example:
a=0
command="echo \"$a\""
for i in {1..2}; do
### change variable $a
a="$i"
### print command with the new $a
eval "$command"
done
### (it fails) result:
0
0
I need $a to be reloaded everytime in order to be substituted inside the $command string, thus the loop above will return
### wanted result
1
2
I know there are other strategies to achieve this, but I wonder if there is a specific way to reload a variable inside a string
Thank you very much in advance for any help!
You can use a function instead of a variable assignment
#!/usr/bin/env bash
a=0
command(){ echo "$1" ; }
for i in {1..2}; do
a="$i"
command "$a"
done
Edit: as per #glenn jackman one can use a global variable
command(){ echo "$a"; }
And just call the function without the argument $a
command
When you put a variable inside " its expanded. Use a single quote for command variable assignment.
$a=0
$command="echo \"$a\""
$echo $command
echo "0"
$command='echo \"$a\"'
$echo $command
echo \"$a\"
$
Try
a=0
command='echo $a'
for i in {1..2}; do
### change variable $a
a="$i"
### print command with the new $a
eval "$command"
done
Related
I am currently trying to rename an input argument by the variable "i" in the following for loop:
cd $1
num=$(echo $#)
echo $num
echo $#
echo "This is the next part where I print stuff"
for i in $(seq 2 $num)
do
echo $i
echo ${!i}
Args_array+=$(printf '${arg_%s[#]}' ${i})
echo $Args_array
arg_${i}=$(ls ${!i})
done
The output is as follows:
4
output_folder /path/to/my.tsv /path/to/my2.tsv /path/to/my3.tsv
2
/path/to/my.tsv
${arg_2[#]}
/var/spool/slurm/d/job6985121/slurm_script: line 23: arg_2=/path/to/my.tsv: No such file or directory
But it will not allow me to rename the $2, $3 arguments with "i" like this. Any help would be appreciated.
I want to pass these arguments into R and have to put them in arg_1, arg_2, etc. format.
Not sure I understand what's being attempted with Args_array so focusing solely on OP's comment: 'have to put them in arg_1, arg_2' and skipping arg_1 since OP's code doesn't appear to care about storing $1 anywhere; then again, is R not capable of processing input parameters from the command line?
One bash idea:
$ cat testme
#!/usr/bin/bash
num=$#
for ((i=2;i<=$num;i++))
do
declare args_$i=${!i}
done
for ((i=2;i<=$num;i++))
do
typeset -p args_$i
done
Taking for a test drive:
$ testme output_folder /path/to/my.tsv /path/to/my2.tsv /path/to/my3.tsv
declare -- args_2="/path/to/my.tsv"
declare -- args_3="/path/to/my2.tsv"
declare -- args_4="/path/to/my3.tsv"
Suppose I have a script named dd.sh, and I run it like this
./dd.sh sample$name.mp4
So $1 is the string sample$name.mp4.
echo '$1' // shows $1
echo "$1" // shows "sample.mp4"; want "sample$name.mp4"
Then how to process $1 that I can detect whether there is a dollar sign in parameter $1
I want to process the string to sample\$name.mp4 or just detect whether there is a dollar sign in parameter $filename
As you know, a dollar sign marks a variable. You have to take it into account when you are typing it.
You can escape the dollar
./dd.sh "sample\$name.mp4"
or just type it with single quotes
./dd.sh 'sample$name.mp4'
To check if there is a dollar sign in a variable, do
[[ $variable == *\$* ]] && echo 'I HAZ A DOLAR!!!' || echo 'MEH'
One option:
# Replace occurrences of $ with \$ to prevent variable substitution:
filename="${filename//$/\\$}"
I just realized my prompt was showing foo rather than foo$bar$baz as the name of the current branch. foo$bar$baz was getting assigned to PS1 and $bar and $baz were then expanded. Escaping the dollar signs before including the branch name in PS1 prevents unwanted expansions.
Your issue is not with the echo but with the assignment to $filename.
You say
filename="sample$name.mp4"
This will interpolate the string, which means expanding the variable $name. This will result in $filename having the value sample.mp4 (since $name is presumably undefined, which means it expands to an empty string)
Instead, use single quotes in the assignment:
filename='sample$name.mp4'
echo "$filename" will now result in the expected sample$name.mp4. Obviously, echo '$filename' will still just print $filename because of the single quotes.
If your question is:
Then how to process $1 that I can detect whether there is a dollar
sign in parameter $1
You can try this:
if [[ $1 == *'$'* ]]
then
echo '$ was found'
else
echo '$ was not found'
fi
Output:
$ ./dd.sh 'sample$name.mp4' // prints $ was found
$ ./dd.sh 'samplename.mp4' // prints $ was not found
For example you have .env file with variables and password for postgres DB. As you know password should be urlencoded course % sing in password. So we have a problem here. Because BASH ignore $ and we get always wrong password for encode.
.env file
DB_NAME=sone_db
DB_PASS=A1$Bb%!Y$ # with dollar signs
...
bash script
#!/bin/bash
PSQL_COMMAND="DROP schema public CASCADE;"
PSQL_COMMAND+="CREATE schema public;"
set -o allexport
# set source file and get access to all variables in .env
source /path/.env
ENCODED_PASS=$(python -c "from urllib.parse import quote; print(quote('$DB_PASS'))");
psql postgres://$DB_USER:$ENCODED_PASS#$DB_HOST:5432/$DB_NAME -c "$PSQL_COMMAND"
echo $DB_PASS # returns A1%!Y$
echo '$DB_PASS' # returns $DB_PASS
echo "$DB_PASS" # returns A1%!Y$
# disables variables
set +o allexport
# Wont work because BASH find $ sing in string and think that is variable,
so in first and last echo missed part $Bb%
To resolve this you need in .env file escape string in single quote
...
DB_PASS='A1$Bb%!Y$'
...
Demo:
Evidently, the single quotes ' results in no interpolation of enclosing characters.
cat > test.sh
echo '$1'
echo "$1"
% ./test.sh hello
$1
hello
% ./test.sh hello$world
$1
hello
% ./test.sh hello\$world
$1
hello$world << Looks as expected
% ./test.sh 'hello\$world'
$1
hello\$world
% ./test.sh "hello\$world"
$1
hello$world << Looks as expected
I'm recently learning bash and confused when a variable would add $. I find code like:
i=1
while [ $i -le 10 ]
do
echo "$n * $i = `expr $i \* $n`"
i=`expr $i + 1`
done
The $ substitutes the variable. Writing $i will insert the value of i, no matter where you write it.
If you want to assign to the variable, that obviously makes no sense.
I thought #slaks' [ answer ] wouldn't be complete without this :
When not to add $ for a variable
With The Double-Parentheses [ Construct ]
x=5;
(( x++ )) # fine, note this construct accept $x form too.
When using export
var=stuff
export var #fine
When using declare
declare -a arry # fine
When not omit $
As #rici pointed out in the comment below:
you can leave out the $ in any arithmetic context, not just ((...))
and $((...)) ... For example, if arr is an array (not associative), then
${arr[x++]} is also fine.
Consider
# You wanted to create an associative array 'test' but you forgot to do
# declare -A test , Now below
test[foo]=bar # is foo a variable or a key, the reader isn't clear
# creates a simple array
echo ${test[foo]} # is foo a variable or a key?
bar
declare -p test
declare -a test='([0]="bar")'
# What happened?
# Since foo was not set at the point when 'test[foo]=bar' was called,
# bash substituted it with zero
# I meant to say test[foo]=bar hides an error.
A key thing to remember is that variables are never passed around in shell, only values. When you call something like
echo "$foo"
you might think that echo receives $foo, then looks at its value. Instead, the shell first expands $foo to the value of foo, then passes that value to echo.
The dollar sign is used to introduce any such parameter expansion, where the value of a parameter is needed. Consider:
$ foo=10
$ echo foo
foo
$ echo $foo
10
From the perspective of the echo command, there is no difference between echo $foo and echo 10; in both cases, the value passed to echo is 10.
To set a value to a variable in bash you can do
a=10
Where as to access the value of that variable you need to use
echo $a which mean $ is a symbol used to access the value of a variable.
i=1 ---> setting variable as 1
while [ $i -le 10 ] ---> simple while statement which loops till value of i is less that 10
do
echo "$n * $i = `expr $i \* $n`" ---> This is a syntax error bcoz value of n is never assigned
i=`expr $i + 1` ---> This line add's one to value of i
done ---> terminate while loop
Hope that explains you.
I've got two sh files, which are "main.sh" and "sub.sh" i want to return a variable's value inside "sub.sh" and use it inside main.sh .There is so many "echo" command so i can't just return the value from sub.sh file. I need only one variable's value. How can that be possible?
main.sh
echo "start"
//how to get a variable from the sh below?
//dene=$(/root/sub.sh)
echo "finish"
sub.sh
echo "sub function"
a="get me out of there" // i want to return that variable from script
echo "12345"
echo "kdsjfkjs"
To "send" the variable, do this:
echo MAGIC: $a
To "receive" it:
dene=$(./sub.sh | sed -n 's/^MAGIC: //p')
What this does is to discard all lines that don't start with MAGIC: and print the part after that token when a match is found. You can substitute your own special word instead of MAGIC.
Edit: or you could do it by "source"ing the sub-script. That is:
source sub.sh
dene=$a
What that does is to run sub.sh in the context of main.sh, as if the text were just copy-pasted right in. Then you can access the variables and so on.
main.sh
#!/bin/sh
echo "start"
# Optionally > /dev/null to suppress output of script
source /root/sub.sh
# Check if variable a is defined and contains sth. and print it if it does
if [ -n "${a}" ]; then
# Do whatever you want with a at this point
echo $a
fi
echo "finish"
sub.sh
#!/bin/sh
echo "sub function"
a="get me out of there"
echo "12345"
echo -e "kdsjfkjs"
exit 42
You can export variable to shell session in sub.sh and catch it later in main.sh.
sub.sh
#!/usr/bin/sh
export VARIABLE="BLABLABLA"
main.sh
#!/bin/sh
. ./sub.sh
echo $VARIABLE
I have a bash loop, I'm trying to read the all variables:
var1="hello1"
var2="hello2"
var3="hello3"
for i in `seq 1 3`;
do
ab=var$i
# Now ab == var1, I want to echo $var1
done
I'm trying to get dynamically var(1)(2)(3) and get out the String of it.
Edit:
The point here is how to concatenation variables like ab=var$i
and using the ab variable (var1 for example) as a variable, I mean to get the var1 value hello1
I didn't mean how to do it to this specific example, and not with arrays.
Hope I have clarified myself.
var1="hello1"
var2="hello2"
var3="hello3"
for i in `seq 1 3`;
do
ab=var$i
echo ${!ab}
done
I'm not sure it is the best solution to your larger problem, but it is the direct solution to your immediate request.
Simpler approach:
var1="hello1"
var2="hello2"
var3="hello3"
eval echo\ $var{1..3}\;
Is expanded to:
echo $var1
echo $var2
echo $var3
Ouput:
hello1
hello2
hello3