Read commands from test file and execute - bash

I am trying to write a shell testing program which compares the output for my program with the sample program. I have stored a list of command in a text file, it looks like this:
commands.txt:
echo line A > a
echo line A > b
./program a b
and the shell test looks like this:
cat $testname | while read LINE
do
echo -e "$LINE$"
$LINE
done
but rather than crating files a and b the program produces the flowing:
echo line A > a
line A > a
echo line B > b
line B > b
How can I execute the command just like it was written in the shell file and redirect the out put to another file?

I think the only way to do that is to use eval:
cat "$testname" | while read -r; do
echo "$REPLY"
eval "$REPLY"
done
If you just run $LINE, it will perform word splitting, but not I/O redirection, so it'll just pass > as a normal argument to echo.

The shell processes redirections before word expansion, which means that the > inside the string is not interpreted by the shell in this context. You need to request explicitly that the string is interpreted as a full command, like this:
eval "$LINE"

If you would like to write the exact same lines inside of the commands.txt file, into another file, you can say;
echo "$line" >> WriteTheLines.txt
If you would like to execute the commands inside of the commands.txt file, and write the output of the commands into another file, you can say;
eval "$line" >> ExecuteTheCommands.txt
So as an example;
#!/bin/bash
input="/home/commands.txt"
while read line
do
echo "$line" >> WriteTheCommands.txt
eval "$line" >> ExecuteTheCommands.txt
done<"$input"

Related

Store multiline eval output in variable bash

Can someone help me to store multiline output in variable in bash. I have the following code:
# FILES[1] contents:
# age people.csv
# ...data...
FILE="${FILES[1]}"
cmd=$(head -n 1 "$FILE")
cmd="./corona $cmd"
echo "Command to run: ${cmd[*]}"
output=$(eval "$cmd")
echo "$output"
I'm trying to store the output of corona script in output variable. But it doesn't seem to work. The output stucks at
Command to run: ./corona age people.csv
And on the second line I can see only the blinking cursor. But when I press Ctrl+D it suddenly prints all the output from corona script and stops. So, probably, the echo command works just after pressing the shortcut.
Also, I'd like to mention, that variable FILES is an array of filenames. So the FILE variable is a name of the file. It has command arguments to run on the first line and other data starting from the second line.
Here is a sample script I developed to read the output of ls into a variable. You could use the same technique.
#!/bin/bash
my_array=()
while IFS= read -r line; do
my_array+=( "$line" )
done < <( ls )
echo ${#my_array[#]}
printf '%s\n' "${my_array[#]}"

Reading a file line by line from variable

I'm working on a script and it isn't clear how read -r line knows which variable to get the data from.. I want to read line by line from the FILE variable.
Here is the script I'm working on:
#!/bin/bash
cd "/"
FILE="$(< /home/FileSystemCorruptionTest/*.chk)"
while read -r line
do
echo "$line" > /home/FileSystemCorruptionTest/`date +%Y_%m_%d_%H_%M_%S`_1.log
done
echo "" > /home/FileSystemCorruptionTest/Done
Since it looks like you want to combine multiple files, I guess that I would regard this as a legitimate usage of cat:
cat /home/FileSystemCorruptionTest/*.chk | while read -r line
do
echo "$line"
done > /home/FileSystemCorruptionTest/`date +%Y_%m_%d_%H_%M_%S`_1.log
Note that I moved the redirect out of the loop, to prevent overwriting the file once per line.
Also note that your example could easily be written as:
cat /home/FileSystemCorruptionTest/*.chk > /home/FileSystemCorruptionTest/`date +%Y_%m_%d_%H_%M_%S`_1.log
If you only actually have one file (and want to store it inside a variable), then you can use <<< after the loop:
while read -r line
do
echo "$line"
done <<<"$FILE" > /home/FileSystemCorruptionTest/`date +%Y_%m_%d_%H_%M_%S`_1.log
<<< "$FILE" has the same effect as using echo "$FILE" | before the loop but it doesn't create any subshells.
What you are requesting:
echo "${FILE}" | while read -r line …
But I think Tom's solution is better.

Bourne Shell - Read and print tab from file

I am trying, so far unsuccessfully to read and print a tab character from a file in a Bourne shell script.
For example, here is my file, in.txt (stackoverflow won't let me write a tab, so replace [tabcharacter] with a tab):
[tabcharacter]Hello World!
My script as as follows:
#!/bin/sh
while read line
do
echo -e "${line}" >> out.txt
/bin/echo -e "${line}" >> out.txt
done < "./in.txt"
The out.txt I get is:
-e hello!
hello!
Whereas I would expect from one of these the output to be the same as in.txt.
I think it's a problem with the way I use the read command. But I'm not sure how I can get it to read tabs.
Any help much appreciated.
#!/bin/sh
export IFS=
while read line
do
echo -e "$line" >> out.txt
/bin/echo -e "$line" >> out.txt
done < "./in.txt"
I seted the IFS variable to a empty string, now its working, please test it!

Redirected output is interpreted when file is given as a variable

When I do the following within a bash script file:
#!/bin/bash
echo -E $line >> 2.txt
... the $line is written inside 2.txt file without any troubles. However, if I use a variable for the file like this:
#!/bin/bash
file='2.txt'
echo -E $line >> $file
... the escaped \$ is interpreted and in the file only a '$' character is written. Outside of the bash script file (in a Bash console) both codes work. Does anybody know why? I could not get information on that on the Internet.

eval echo "$line" ignoring '&' symbol

I am using the below portion in my script to replace variables in a file.
But after running this portion of the script , the "&" symbol is ignored by the script. Is there a reason for this behaviour ?
while read line
do
eval echo "$line" >> output.txt
done < "input"
My input file looks like below
XXX.6.ID=LCPR_PROJ&
XXX.6.VALUE=$PMS&
XXX.6.CTID=58&
XXX.6.ECID=1032&
XXX.6.SEC=
After running the command , my output looks like below
XXX.6.ID=LCPR_PROJ
XXX.6.VALUE=132
XXX.6.CTID=58
XXX.6.ECID=1032
XXX.6.SEC=
Do I need to alter something in my command ?
You don't want to use eval!
eval will evaluate the expression separately, and interpret the & character.
The & character tells bash to run the command in a subshell. From the Bash man page:
If a command is terminated by the control operator &, the shell executes the command in the background in a subshell.
Remove it from your script
while read line
do
echo "$line" >> output.txt
done < "input"
and it will work as expected.
If you do want to run every line through eval, and you know what you're doing, then you will have to manually detect and escape the &s:
while read line; do
line=${line/&/\\&}
eval echo "$line";
done
By using bash's string manipulation.

Resources