Get a file content in Bash after expanding its variables - bash

cat file
$VAR
cat script
#!/bin/bash
CONTENT=$(<file)
echo $CONTENT
./script
$VAR
I'd like to get the variable's actual value, not "$VAR". How to get a weaker quoting? Many thanks!

This should do it:
CONTENT=$(eval echo -e `<file`)

Related

Bash Script that Creates a File with a Variable in the Filename

I am trying to write a variable into a file and also use the variable as the name of the file itself. Any ideas?
EXAMPLE 1: Filename and content within that file should be "helloworld"
#/bin/bash
OUTPUT="helloworld"
echo $OUTPUT > ~/Desktop/directory/outputs/$OUTPUT.txt
EXAMPLE 2: Filename and content within file should be "hellokitty"
#/bin/bash
OUTPUT="hellokitty"
echo $OUTPUT > ~/Desktop/directory/outputs/$OUTPUT.txt
This should work
#!/usr/bin/env bash
OUTPUT=hellokitty
echo "$OUTPUT" > ~/Desktop/directory/outputs/"${OUTPUT}".txt
You need to tell bash where your variable starts and where it ends. You can do this by using "${OUTPUT}" instead of just "$OUTPUT".
If you really want to do it that way, just use a 2-step, e.g.:
#!/bin/bash
output="helloword"
filename="$HOME/Desktop/directory/outputs/${output}".txt
echo "$output" > "$filename"

Cant access the variable as variable stored in a file using bash

I have a bash script like
source ./testscript
while read line
do
echo "$line"
done < "test.file"
where the testscript is like
VAR="hello"
the test.file is like
"$VAR" world!!!
I expect the output of my bash script to be
hello world!!!
but what i get is
"$VAR" world!!!
Is there any solution?
you can try
echo `eval "echo $line"`
instead of
echo "$line"
You don't want to use eval. eval would allow arbitrary code to be embedded into your (text?) file which is certainly not what you want, especially if untrusted users have write access to said file.
If you don't need to expand arbitrarily named variables you can do something like the following, but there might be a better approach to the problem you are actually trying to solve.
$ cat t.sh
#!/bin/bash
VAR1=hello
VAR2='!!!'
FOO=test
expand_vars()
{
local s=$*
local var
for var in VAR{1..9} FOO; do
s=${s//%${var}%/${!var}}
done
echo "${s}"
}
while read line; do
line=$(expand_vars "${line}")
echo "${line}"
done <<__DATA__
%VAR1% world%VAR2%
This is a %FOO%
__DATA__
.
$ ./t.sh
hello world!!!
This is a test

how to read data from a file in shell script

I have two shell script files test1.sh and test2.sh . I have another file called translogs.txt.
Now I need to copy the values of two variables in test1.sh to translog.txt and the same variables need to be copied to the corresponding values in test2.sh.
test1.sh
#!/bin/sh
ONE="000012"
TIME="2013-02-19 15:31:06"
echo -e "$ONE\n$TIME">translog.txt;
translog.txt
ONE="000012"
TIME="2013-02-19 15:31:06"
But here in test2.sh, I want the same value as in translog.txt to the corresponding variable
test2.sh
#!/bin/sh
ONE="000012"
TIME="2013-02-19 15:31:06"
1 Diry solution
$> cat translog.txt
ONE="000012"
TIME="2013-02-19 15:31:06"
With perl regular expression grep could match these value using lookbehind operator.
$> grep --only-matching --perl-regex "(?<=ONE\=).*" translog.txt
"000012"
And for TIME:
$> grep --only-matching --perl-regex "(?<=TIME\=).*" translog.txt
"2013-02-19 15:31:06"
So from withing the test2.sh script you can use it like this:
#!/bin/bash
ONE=`grep --only-matching --perl-regex "(?<=ONE\=).*" translog.txt`
TIME=`grep --only-matching --perl-regex "(?<=TIME\=).*" translog.txt`
2 Command line solution
Another solution pointed out in one of the links below would be to use:
the source (a.k.a. .) command to load all of the variables in the file into the current shell:
$ source translog.txt
Now you have access to the values of the variables defined inside the file:
$ echo $TIME
"2013-02-19 15:31:06"
3 Easiest solution
Another approach was mentioned by #user2086768. Put these lines to `test2.sh:
#!/bin/bash
eval $(cat translog.txt)
And as a result you would have assigned the two variables within the test2.sh script:
ONE="000012"
TIME="2013-02-19 15:31:06"
you can easily check that adding:
echo $ONE
echo $TIME
Check also these links:
how to get value of variable config in bash?
Here's a more general overview: Loading data into bash variables
As translog.txt is valid bash code, you could do:
source translog.txt
in test2.sh, ONE and TWO would be available in test2.sh.
A word of warning, that does open you up to shell script injection attacks if the values for ONE and TWO were to come from an untrusted source.
If your translog.txt is as you say, then this will work
#!/bin/sh
while read aa
do
eval "$aa"
done < translog.txt
eval should work for you.
Try to use this version of test2.sh:
test2.sh
#!/bin/bash
eval $(cat translog.txt)
echo $ONE
echo $TIME
This outputs:
000012
2013-02-19 15:31:06

How to expand shell variables in a text file?

Consider a ASCII text file (lets say it contains code of a non-shell scripting language):
Text_File.msh:
spool on to '$LOG_FILE_PATH/logfile.log';
login 'username' 'password';
....
Now if this were a shell script I could run it as $ sh Text_File.msh and the shell would automatically expand the variables.
What I want to do is have shell expand these variables and then create a new file as Text_File_expanded.msh as follows:
Text_File_expanded.msh:
spool on to '/expanded/path/of/the/log/file/../logfile.log';
login 'username' 'password';
....
Consider:
$ a=123
$ echo "$a"
123
So technically this should do the trick:
$ echo "`cat Text_File.msh`" > Text_File_expanded.msh
...but it doesn't work as expected and the output-file while is identical to the source.
So I am unsure how to achieve this.. My goal is make it easier to maintain the directory paths embedded within my non-shell scripts. These scripts cannot contain any UNIX code as it is not compiled by the UNIX shell.
This question has been asked in another thread, and this is the best answer IMO:
export LOG_FILE_PATH=/expanded/path/of/the/log/file/../logfile.log
cat Text_File.msh | envsubst > Text_File_expanded.msh
if on Mac, install gettext first: brew install gettext
see:
Forcing bash to expand variables in a string loaded from a file
This solution is not elegant, but it works. Create a script call shell_expansion.sh:
echo 'cat <<END_OF_TEXT' > temp.sh
cat "$1" >> temp.sh
echo 'END_OF_TEXT' >> temp.sh
bash temp.sh >> "$2"
rm temp.sh
You can then invoke this script as followed:
bash shell_expansion.sh Text_File.msh Text_File_expanded.msh
If you want it in one line (I'm not a bash expert so there may be caveats to this but it works everywhere I've tried it):
when test.txt contains
${line1}
${line2}
then:
>line1=fark
>line2=fork
>value=$(eval "echo \"$(cat test.txt)\"")
>echo "$value"
line1 says fark
line2 says fork
Obviously if you just want to print it you can take out the extra value=$() and echo "$value".
If a Perl solution is ok for you:
Sample file:
$ cat file.sh
spool on to '$HOME/logfile.log';
login 'username' 'password';
Solution:
$ perl -pe 's/\$(\w+)/$ENV{$1}/g' file.sh
spool on to '/home/user/logfile.log';
login 'username' 'password';
One limitation of the above answers is that they both require the variables to be exported to the environment. Here's what i came up with that would allow the variables to be local to the current shell script:
#!/bin/sh
FOO=bar;
FILE=`mktemp`; # Let the shell create a temporary file
trap 'rm -f $FILE' 0 1 2 3 15; # Clean up the temporary file
(
echo 'cat <<END_OF_TEXT'
cat "$#"
echo 'END_OF_TEXT'
) > $FILE
. $FILE
The above example allows the variable $FOO to be substituted in the files named on the command line. I'm sure it can be improved, but this works for me so far.
Thanks to both previous answers for their ideas!
If the variables you want to translate are known and limited in number, you can always do the translation yourself:
sed "s/\$LOG_FILE_PATH/$LOG_FILE_PATH/g" input > output
And also assuming the variable itself is already known
This solution allows you to keep the same formatting in the ouput file
Copy and paste the following lines in your script
cat $1 | while read line
do
eval $line
echo $line
eval echo $line
done | uniq | grep -v '\$'
this will read the file passed as argument line by line, and then process to try and print each line twice:
- once without substitution
- once with substitution of the variables.
then remove the duplicate lines
then remove the lines containing visible variables ($)
Yes eval should be used carefully, but it provided me this simple oneliner for my problem. Below is an example using your filename:
eval "echo \"$(<Text_File.msh)\""
I use printf instead of echo for my own purposes, but that should do the trick. Thank you abyss.7 providing the link that solve my problem. Hope it helps.
Create an ascii file test.txt with the following content:
Try to replace this ${myTestVariable1}
bla bla
....
Now create a file “sub.sed” containing variable names, eg
's,${myTestVariable1},'"${myTestVariable1}"',g;
s,${myTestVariable2},'"${myTestVariable2}"',g;
s,${myTestVariable3},'"${myTestVariable3}"',g;
s,${myTestVariable4},'"${myTestVariable4}"',g'
Open a terminal move to the folder containing test.txt and sub.sed.
Define the value of the varible to be replaced
myTestVariable1=SomeNewText
Now call sed to replace that variable
sed "$(eval echo $(cat sub.sed))" test.txt > test2.txt
The output will be
$cat test2.txt
Try to replace this SomeNewText
bla bla
....
#logfiles.list:
$EAMSROOT/var/log/LinuxOSAgent.log
$EAMSROOT/var/log/PanacesServer.log
$EAMSROOT/var/log/PanacesStrutsGUI.log
#My Program:
cat logfiles.list | while read line
do
eval Eline=$line
echo $Eline
done

How can I use bash to parse out only a section of a variable with different delimiters?

I have a loop in a bash file to show me all of the files in a directory, each as its own variable. I need to take that variable (filename) and parse out only a section of it.
Example:
92378478234978ehbWHATIWANT#98712398712398723
Now, assuming "ehb" and the pound symbol never change, how can I just capture WHATIWANT into its own variable?
So far I have:
#!/bin/bash
for FILENAME in `dir -d *` ; do
done
You can use sed to edit out the parts you don't want.
want=$(echo "$FILENAME" | sed -e 's/.*ehb\(.*\)#.*/\1/')
Or you can use Bash's parameter expansion to strip out the tail and head.
want=${FILENAME%#*}; want=${want#*ehb}
One possibility:
for i in '92378478234978ehbWHATIWANT#98712398712398723' ; do
j=$(echo $i | sed -e 's/^.*ehb//' -e 's/#.*$//')
echo $j
done
produces:
WHATIWANT
using only the bash shell, no need external tools
$ string=92378478234978ehbWHATIWANT#98712398712398723
$ echo ${string#*ehb}
WHATIWANT#98712398712398723
$ string=${string#*ehb}
$ echo ${string%#*}
WHATIWANT

Resources