Strange variable assignment using read - bash

I'm using bash in the WSL (via Terminus) and I'm trying to read in a csv file using the following:
INPUT=student_lookup.csv
IFS=','
[ ! -f $INPUT ] && { echo "$INPUT file not found"; exit 99; }
while read st1 st2
do
fsrc1="./test_rep/*$st1*.org" ;
fsrc1=${fsrc1,,}
fsrc2="./test_rep/*$st2*.org" ;
fsrc2=${fsrc2,,}
echo "$fsrc1"
echo "$fsrc2"
done < $INPUT
The problem is my output looks like:
./test_rep/*AAABBB001*.org
*.orgt_rep/*AAACCC002
./test_rep/*BBBCCC002*.org
*.orgt_rep/*BBBDDD003
The first variable assignment is happening as expected, but I'm confused as to why the second variable is overwriting the start of the variable rather than appending *.org to the end? I'm reading in student numbers (I've changed the letters of the student numbers, but the format is the same).
My input file looks like
1 AAABBB001,AAACCC002
1 BBBCCC002,BBBDDD003
2 CCCDDD003,CCCEEE004
Edit: seems like the dos line endings were the problem
I resolved it by stripping the first 9 letters from the read line, i.e.
fsrc2="./test_rep/*${st2:0:9}*.org" ;

Related

Unix looping from text file

I have 2 text files. I want to loop in the first file to get a list, then using that list, loop from the second file to search for matching fields.
The first loop was fine, but when the second loop comes in, the variable $CLIENT_ABBREV cannot be read in the second loop, it's reading as blank. Output looks like does not match DOG where there's a blank before does.
while IFS=',' read CLIENT_ID NAME SERVER_NAME CLIENT_ABBREV
do
echo "\n------------"
echo Configuration in effect for this run
echo CLIENT_ID=$CLIENT_ID
echo NAME=$NAME
echo SERVER_NAME=$SERVER_NAME
echo CLIENT_ABBREV=$CLIENT_ABBREV
while IFS=',' read JOB_NAME CLIENT_ABBREV_FROMCOMMAND JOBTYPE JOBVER
do
if [ "$CLIENT_ABBREV" == "$CLIENT_ABBREV_FROMCOMMAND" ]; then
# do something
else
echo $CLIENT_ABBREV does not match $CLIENT_ABBREV_FROMCOMMAND
done <"$COMMAND_LIST"
done <"$CLIENT_LIST"
Is there a file with the name COMMAND_LIST ?
Or, actually do you want to use $COMMAND_LIST instead of COMMAND_LIST ?

Read multi variable csv bash build multi line file from it

I had what I thought was a simple concept which I could easily do as I did something similar.
I have an input file input.csv
1a,1b
2a,2b
I would like the following output
Output file 1
This is variable 1 named 1a ok
This is variable 2 named 1b ok
Output file 2
This is variable 1 named 2a ok
This is variable 2 named 2b ok
I thought I could do something similar to below
i=1
while IFS=, read var1 var2; do
echo This is variable 1 named "var1" > filenamei
echo This is variable 2 named "var2" >> filenamei
i=i+1
done </inputfile.csv
I previously wrote code to take a single variable from a long file and write output to a single file and it worked fine. Like below
Input file
a
b
Single output file
This is A
This is B
Script was
while read p;do
echo this is "$p" >>output file
done < input file
Been through lots of different errors but getting nowhere.
It will be easy by configuring double loop: the outer loop to iterate over lines and the inner one for comma-separated fields. Then how about:
#!/bin/bash
i=1
while read -r line; do
ifs_back="$IFS"
IFS=","
set -- $line
for ((j=1; j<=$#; j++)); do
echo This is variable "$j" named "${!j}" >> "filename${i}"
done
IFS="$ifs_back"
i=$((i+1))
done < "inputfile.csv"
Explanations:
In order to split the input line with commas, we temporarily set IFS to "," then assign the fields to positional parameters $1, $2.
The loop counter j for the inner loop starts with 1 and ends with $#1, number of fields.
We can access the value of the positional parameter via ${!j}.
As a clean up of the inner loop, we retrieve IFS and increment i for the next line.
The code above is flexible with #lines and #fields so would work with the input:
1a,1b
2a,2b
3a,3b
as wel as with:
1a,1b,1c
2a,2b,2c
3a,3b,3c
Hope this helps.

Formatting need to change for text file in bash scripting

I have below output from a text file. This is long file i just copy here some rows only.
HP83904B74E6
13569.06
7705.509999999999
HP4DC2EECAA8
4175.1
2604.13
And i want to print it like below.
HP83904B74E6 13569.06 7705.509999999999
HP4DC2EECAA8 4175.1 2604.13
I have tried by reading the file line by live using while loop and try to store the value of variable e.g. variablename$i so that i can print it like variablename0 and after every 3 line i have used If statement to print the value of variablename0 variablename1 variablename2, but did not work for me.
Use pr:
$ pr -a3t tmp.txt
HP83904B74E6 13569.06 7705.509999999999
HP4DC2EECAA8 4175.1 2604.13
i have tried by reading the file line by live using while loop and try to store the value of variable e.g. variablename$i so that i can print it like variablename0 and after every 3 line i have used If statement to print the value of variablename0 variablename1 variablename2, but did not work for me. I am just learning bash.
while read -r a; do
read -r b;
read -r c;
echo "$a $b $c";
done < file
you get,
HP83904B74E6 13569.06 7705.509999999999
HP4DC2EECAA8 4175.1 2604.13

read multiple values from a property file using bash shell script

Would like to read multiple values from a property file using a shell script
My properties files looks something like below, the reason I added it following way was to make sure, if in future more students joins I just need to add in in the properties file without changing any thing in the shell script.
student.properties
total_student=6
student_name_1="aaaa"
student_name_2="bbbb"
student_name_3="cccc"
student_name_4="dddd"
student_name_5="eeee"
When I run below script I not getting the desired output, for reading the student names from properties file
student.sh
#!/bin/bash
. /student.properties
i=1
while [ $i -lt $total_student ]
do
{
std_Name=$student_name_$i
echo $std_Name
#****** my logic *******
} || {
echo "ERROR..."
}
i=`expr $i + 1`
done
Output is something like this
1
2
3
4
5
I understand the script is not getting anything for $student_name_ hence only $i value is getting printed.
Hence, wanted to know how to read values from the properties file.
You can do variable name interpolation with ${!foo}. If $foo is "bar", then ${!foo} gives you the value of $bar. In your code that means changing
std_Name=$student_name_$i
to
var=student_name_$i
std_Name=${!var}
Alternatively, you could store the names in an array. Then you wouldn't have to do any parsing.
student.properties
student_names=("aaaa" "bbbb" "cccc" "dddd" "eeee")
student.sh
#!/bin/bash
. /student.properties
for student_name in "${student_names[#]}"; do
...
done
You can use indirect expansion:
std_Name=student_name_$i
echo "${!std_Name}"
the expression ${!var} basically evaluates the variable twice:
first evaluation: student_name_1
second evaluation: foo
Note that this is rarely a good idea and that using an array is almost always preferred.

Variable assignment when reading from file using cat

I have a txt file that is in the format below:
name1 path/to/some/directory
name2 path/to/some/other/directory
name3 path/to/some/directory
name4 path/to/some/other/directory
...
Here is the code I have written to read this file line by line:
NUM=1
for line in $(cat /path/to/my/file.txt); do
if [ $((NUM%2)) -eq 1 ]
then
name= $line #this line does not work
echo $line #while this line works just fine
else
sudo tar -cf /desired/path/$name.tar $line
fi
NUM=$((NUM+1))
done
This code actually reads file word by word, and it alternates between then and else of if statement. Once it assigns a value it has read to variable name (then part inside if), then it uses that variable in command that is performed in else part of if. (This is how I expect it to work.)
The problem that arises is that variable assignment in then part of if seems not to work, it sees word it has just read as command, and doesn't assign its value to variable. I tried to echo it and it works just fine.
Why name= $line variable assignment is not working?
Thank you for any suggestions, comments or answers.
The assignments in bash require no space around =.
Hence, you need to say:
name="$line"
^ ^
quotes!
This happens because anything happening after the declaration is considered a command. See for example this, that tries to define r to 2 and then echo 1 is executed:
$ r=2 echo 1
1
This is why it is also a good thing to quote the declaration: name="$line".
Regarding the parsing and definition of variables of the file, you can maybe use this approach:
declare $('s/\s\+/="/; s/$/"/' a)
This replaces the spaces in between the first and second word by =" and the end of line with ". This way, name /path/ gets converted into name="/path/". By using declare, this command gets executed and makes variables be ready for use.
$ cat a
name1 aa
name2 rr
name5 hello
$ sed 's/\s\+/="/; s/$/"/' a
name1="aa"
name2="rr"
name5="hello"
$ declare $('s/\s\+/="/; s/$/"/' a)
So now you have the variables ready to use:
$ echo "$name5"
hello
And finally, note that this is equivalent (and better) than for line in $(cat /path/to/my/file.txt):
while IFS= read -r val1 val2 ...
do
... things ...
done < /path/to/my/file.txt

Resources