How to use a text file for multiple variable in bash - bash

I want to make an bash script for things I use much and for easy access of things but I want to make an firstrun setup that saves the typed paths to programs or commands in a txt file. But how can I do that. And how can I include the lines of the text file to multiple variables?
After a lot of testing I could use the 2 anwsers given. I need to store a variable directly to a textfile and not asking a user for his details and then stores that to a file
So I want it to be like this
if [[ -d "/home/$(whoami)/.minecraft" && ! -L "/home/$(whoami)/.minecraft" ]] ; then
echo "Minecraft found"
minecraft="/home/$(whoami)/Desktop/shortcuts/Minecraft.jar" > safetofile
# This ^ needs to be stored on a line in the textfile
else
echo "No Minecraft found"
fi
if [[ -d "/home/$(whoami)/.technic" && ! -L "/home/$(whoami)/.technic" ]]; then
echo "Technic found"
technic="/home/$(whoami)/Desktop/shortcuts/TechnicLauncher.jar" > safetofile
# This ^ also needs to be stored on an other line in the textfile
else
echo "No Technic found"
fi
I really want to have an anwser to this because I want to script bash. I already experience in bash scripting.

Here's an example:
#!/bin/bash
if [[ -f ~/.myname ]]
then
name=$(< ~/.myname)
else
echo "First time setup. Please enter your name:"
read name
echo "$name" > ~/.myname
fi
echo "Hello $name!"
The first time this script is run, it will ask the user for their name and save it. The next time, it will load the name from the file instead of asking.

#!/bin/bash
# file to save the vars
init_file=~/.init_vars.txt
# save_to_file - subroutine to read var and save to file
# first arg is the var, assumes init_file already exists
save_to_file()
{
echo "Enter $1:"
read val
# check if val has any spaces in them, you will need to quote them if so
case "$val" in
*\ *)
# quote with double quotes before saving to init_file
echo "$1=\"$val\"" >> $init_file
;;
*)
# save var=val to file
echo "$1=$val" >> $init_file
;;
esac
}
if [[ ! -f $init_file ]]
then
# init_file doesnt exist, this will come here only once
# create an empty init_file
touch $init_file
# vars to be read and saved in file, modify accordingly
for var in "name" "age" "country"
do
# call subroutine
save_to_file "$var"
done
fi
# init_file now has three entries,
# name=val1
# age=val2
# country=val3
# source the init_file which will read and execute commands from init_file,
# which set the three variables
. ${init_file}
# echo to make sure it is working
echo $name $age $country

Related

Shell-write a file into shell variable

I have a file like this format:
a;b;c
e;d;f
how can I use shell to read the file detail information into variables?
I would have 6 variables to store the data.
more detailed information for this is that as the following shows:
I have written a script:
#!/bin/sh
unset ret
ret=0
if [ "$#" -ne 3 ]; then
logger -p err "Usage: $0 eth_name rule_file table_name"
ret=1
exit ret
fi
OFS=$IFS # store field separator
IFS=";" # define field separator
eth_name=$1 # ethernet device name
rule_file=$2 # input file name
table_name=$3 # lookup table name
logger -p notice "$0 $eth_name $rule_file $table_name"
unset a # reference to line array
unset i j # index
unset m n # dimension
### read route configuration
i=0
while read line
do
a=A$i
unset $a
declare -a $a='($line)'
i=$((i+1))
done < $rule_file
# store number of lines
m=$i
# function for apply route
add_route()
{
if [ "source" = "$1" ]; then
src_address=$(ifconfig $eth_name | sed -n 's/.*inet addr:\([0-9.]\+\)\s.*/\1/p')
ip rule add from $src_address lookup $table_name
ret=$?
logger -p notice "ip rule add from $src_address lookup $table_name $ret"
elif [ "default" = "$1" ]; then
ip route add default via $2 table $table_name
ret=$?
logger -p notice "ip route add default via $2 table $table_name $ret"
else
ipaddress_range=$1
gateway_ipaddress=$2
ip route add $ipaddress_range via $gateway_ipaddress dev $eth_name table $table_name
ret=$?
logger -p notice "ip route add $ipaddress_range via $gateway_ipaddress dev $eth_name table $table_name $ret"
fi
}
### apply route configuration
for ((i=0; i < $m; i++))
do
a=A$i
# get line size
# double escape '\\' for sub shell '``' and 'echo'
p0=`eval echo \\${$a[0]}`
p1=`eval echo \\${$a[1]}`
add_route $p0 $p1
done
IFS=$OFS
the rule file's format is as the following shows:
source;
default_route;172.20.5.192/26
default_gateway;172.20.5.254
172.17.23.64/26;172.20.5.254
172.31.252.0/24;172.20.5.254
172.31.254.0/24;172.20.5.254
10.217.1.0/24;172.20.5.254
10.217.2.0/24;172.20.5.254
this script is working normally under the bash environment, now my linux system is not having bash now, this script is not working now, how to change the script to make the script running?
the function for this script is very simple, write every line into the linux system's ip rule and ip route. need to throw 3 variables to make the script running.
You can easily achieve it with read.
#!/bin/bash
while IFS=";" read -r var1 var2 var3; do
command
done <file
exit 0
where:
IFS is your delimiter
varN are your vars, you can use any name you want
N.B. If you need stdin you need to use a file descriptor:
#!/bin/bash
exec 3<file
while IFS=";" read -r var1 var2 var3 <&3; do
command
done
exec 3>&-
exit 0
Further readings here.
N.B.#2 The command read is not the faster solution, usually after 5k lines lose 100 ms compared to other tools (E.G. awk).
The following parses your original sample text and saves fields to sequentially numbered variables, stripping values out of lines using parameter expansion, and doesn't care how many fields you have per line.
#!/bin/sh
i=0
while read line; do
while [ -n "$line" ]; do
eval this_$((i=i+1))="\${line%%;*}"
last="$line"
line="${line#*;}"
[ "$last" = "$line" ] && break
done
done < input.txt
I've tested this successfully with both bash and FreeBSD's /bin/sh (which is based on ash). (Note that FreeBSD's /bin/sh doesn't seem to like arithmetic expressions like $((i++)), but both shells I tested are fine with the notation above.)
But from the look of the script you updated your question with, this isn't what you need. It seems that you have input data with:
one record per line, and
two fields, separated by semicolons.
But I wonder if you even need to store things in variables. It seems to me you'd be looking more for the following type of structure.
#!/bin/sh
...
while IFS=";" read range gateway; do
case "$range" in
source)
: Note that $gateway is blank
;;
default_route)
: do something
;;
default_gateway)
: do something else
;;
[0-9]*)
ip route add "$range" via "$gateway" dev "$eth_name" table "$table_name"
;;
*)
printf 'ERROR: unknown range in rule file: %s\n' "$range" >&2
;;
esac
done < $rule_file
Additional input validation wouldn't hurt.

How to import a config file variable, but use a different separator?

First, source and . are not working as I'm using a different kind of separator, which is something like.
I have tried several methods I can google, but didn't have any luck so far.
I managed to print out all the variables and values correctly, but I can't store it as a variable in this bash process.
What I want:
At end of the bash process when I "echo $HUA_IP:"
it should give me "192.168.0.1" as per the config.cf file.
File config.cf:
"HUA_PASSWORD": "admin",
"HUA_IP": "192.168.0.1"
While my bash file is:
#!/bin/bash
configFile="/opt/config.cf"
# config="`cat $configFile`"
# echo $config
# source $configFile
# echo $var1
# conf="";
while read var value
do
# export "$var"="$value"
var="${var%:*}"
var="${var//\"/}"
var="${var//[\}\{]/}"
value="${value//\"/}"
value="${value//,/}"
# echo "var :'"$var"'"
# echo "value :'"$value"'"
if [ !$var = "" ]
then
# "$var"="$value"
# eval $var=$value
export "$var"="$value"
fi
done < $configFile
echo $HUA_IP:
Try:
while read -r line; do
line=${line//\"/}
declare -x "${line/: /=}"
done<config.cf
echo "$HUA_IP"
When this code is run, the output is:
192.168.0.1
How it works
The key here is that declare, which is a bash builtin, allows you to use a bash variable to create and assign another variable. As a simple example:
$ x="a=b"; declare -x "$x"; echo "$a"
b
Now, let's apply this to your input file:
while read -r line; do
This starts a loop reading one line of input at a time.
line=${line//\"/}
This removes all double-quotes from the input line.
declare -x "${line/: /=}"
This replaces : with = in line and then creates a variable using declare.
The -x option tells bash to export the variable that is declared.
done <config.cf
This tells the loop to get its stdin from config.cf.
Your code, even if it could be not the best approach, is working if you change your if condition. The correct way is:
#...
if [ ! -z $var ]
then
# "$var"="$value"
# eval $var=$value
export "$var"="$value"
fi

Add lines to a document if they do not already exist within the document

I am trying to say, if document does not exist, then create document. Next read each line of the document and if none of the lines match the $site/$name variables, then add the $site/$name variable into the document.
#!/bin/bash
site=http://example.com
doc=$HOME/myfile.txt
if [ ! -f $doc ]
then
touch $doc
fi
read -p "name? " name
while read lines
do
if [[ $lines != $site/$name ]]
then
echo $site/$name >> $doc
fi
done <$doc
echo $doc
echo $site
echo $name
echo $site/$name
echo $lines
Typing test at the read -p prompt the results are
path/to/myfile.txt
http://example.com
test
http://example.com/test
I feel like I should know this but I'm just not seeing it. What am I doing wrong?
If the file is initially empty, you'll never enter the loop, and thus never add the line. If the file is not empty, you'd add your line once for every non-matching line anyway. Try this: set a flag to indicate whether or not to add the line, then read through the file. If you ever find a matching line, clear the flag to prevent the line from being added after the loop.
do_it=true
while read lines
do
if [[ $lines = $site/$name ]]
then
do_it=false
break
fi
done < "$doc"
if [[ $do_it = true ]]; then
echo "$site/$name" >> "$doc"
fi
The following creates the file if it doesn't exist. It then checks to see if it contains $site/$name. If it doesn't find it, it adds the string to the end of the file:
#!/bin/bash
site=http://example.com
doc=$HOME/myfile.txt
read -p "name? " name
touch "$doc"
grep -q "$site/$name" "$doc" || echo "$site/$name" >>"$doc"
How it works
touch "$doc"
This creates the file if it doesn't exist. If it does already exist, the only side-effect of running this command is that the file's timestamp is updated.
grep -q "$site/$name" || echo "$site/$name" >>"$doc"
The grep command sets its exit code to true if it finds the string. If it doesn't find it, then the "or" clause (in shell, || means logical-or) is triggered and the echo command adds the string to the end of the file.

How to loop script till user input is empty?

I am trying to make my script to repeat till the user leaves the block question empty. I just got the loop to run, but I can not find a way to make it possible to stop it when block is empty.
I hope some one can help me!!
#!/bin/tcsh -f
#
set word="start"
until ($word !=""); do
#First ask for Compound and Block Name.
echo -n "please enter block name: "
read block
echo -n "please enter compound name: "
read compound
#Now coping template with new name
#
cp Template $block
#
for line in `cat $block`;do
echo $line | sed -e "s/test1/${block}/g" -e "s/test2/${compound}/g" >>./tmp124.txt
done
mv ./tmp124.txt $block
done
Do you want to use bash or csh? You are using bash syntax but tagged your question csh and call tcsh in the first line of your code.
To answer your question, here are examples of how to iterate on standard input until some input is empty:
For tcsh:
#!/bin/tcsh
while ( 1 )
set word = "$<"
if ( "$word" == "" ) then
break
endif
# rest of code...
end
For bash:
#!/bin/bash
while read word; do
if [ -z $word ]; then
break
fi
# rest of code...
done
Use "Until do" loop,
Eg :
For session variable i am assigning default value, Then entering loop. User can pass any value on each prompt when the value is empty, Loop will Terminate and exit the script.
session="Mysession"
until [$session -eq $null]
do
echo $session
echo "Leave Blank to Terminate session"
read -p "Enter session name : " session
done
echo "Exiting.."

Use part of filename as variable bash

Background:
I have a bunch of filenames named username.sub in single letter directories under script_testing (first letter of username is the folder name). For every username.sub, I need to check if the line user.$username.contacts exists and, if not, append the line followed by a real tab.
Question:
Given the code I have below, why is it not appending to the file? I think I am missing something simple. I keep getting "contacts already subscribed" even if that line is not there.
#!/bin/bash
Path_to_files=/home/user/script_testing/^[A-z]+$/
FULLNAME="${Path_to_files##*/}"
NAME="${FULLNAME%.*}"
if grep 'contacts' $NAME.sub; then
echo 'contacts already subscribed'
else
echo "subscribing to contacts"
echo -e user.$NAME.Contacts \t >> $NAME.sub
fi
You're grepping for the word contacts - which, depending on what else you have in those files, may always be present.
Instead, use grep -q "^user\.$NAME\.Contacts" to look for your line.
Fixed with the following:
#!/bin/bash
#testing directory
#p=$HOME/script_testing
for f in "$p"/*/*.sub ; do
# if this is a file
if [ -f "$f" ]; then
# define variables
F="${f##*/}"
u="${F%%.*}"
cont=$(grep "user.$u.Contacts" "$f")
cal=$(grep "user.$u.Calendar" "$f")
# if our file doesn't contain Contacts subscription
if [ -z "$cont" ]; then
# add Contacts subscription
echo -e "user.$u.Contacts\t" >> "$f"
#fi
# if our file doesn't contain Calendar subscription
elif [ -z "$cal" ]; then
# add Calendar subscription
echo -e "user.$u.Calendar\t" >> "$f"
fi
fi
done
Also added extra line(s) to append. Please, let me know if there is an issue with this so I can learn, but I haven't encountered any problems.

Resources