For loop does not run within function declaration in Shell - linux

My for loop is not running within shell when the function end_process is executed. Similar for loops run outside of a function declaration. I'm wondering why it doesn't run or how to make it run.
function end_process {
{
echo "stopped on $(date)"
echo "$arguments_line"
echo "$invalid_arguments_line"
} >> spy.log
for ((i=0; i<counter; i++)); do
echo "${usernames[$i]}" >> spy.log
echo "test line"
done
echo "007 Signing Out"
exit 0
}
I'm using bash
#!/bin/bash
Also tried this
function end_process {
{
echo "stopped on $(date)"
echo "$arguments_line"
echo "$invalid_arguments_line"
} >> spy.log
for i in `seq 0 $counter`
do
#for ((i=0; i<counter; i++)); do
echo "i is $i"
echo "${usernames[$i]}" >> spy.log
echo "test line"
done
echo "007 Signing Out"
exit 0
}
but neither worked

Problem was that I was calling the function
trap end_process SIGUSR1
but we need to put in escape strings for the function name
trap 'end_process' SIGUSR1
I guess this was just a common problem with RTFM

Related

simple shell script question. please give me advise

i have a question about simple shell script.
this is the source code of rand.sh below
#!/bin/bash
n=$(( RANDOM % 100 ))
if [[ n -eq 42 ]]; then
echo "Something went wrong"
>&2 echo "The error was using magic numbers"
exit 1
fi
echo "Everything went accrding to plan"
and i'm going to make a new shell script, let me call it quiz.sh.
quiz.sh should loop until n==42. if n==42, save the stdout("Something went wrong") and stderr("The error was using magic numbers")
and it finally terminated with printing out those stdout,stderr and Total execution count.
here is my quiz.sh
#!/bin/bash
cnt=0
while [[ "${n}" -ne 42 ]]
do
(( cnt = "${cnt}"+1 ))
source ./rand.sh &> error.txt
done
cat error.txt
echo "${cnt}"
but this is not working. because of exit 1 in rand.sh, the program is terminated before executing cat and echo which is at the end two line.
how can i fix it?? please let me know!
I want to make happen cat error.txt and echo "${cnt}" as well
Run the loop in a subshell
(
while something; do
something
exit 1 # exits only from the subshell
done
)
Note: parent shell doesn't access/inherit child process environment. So cnt is going to be empty in parent shell. Transfer it some other way.
(
cnt=0
while ((n != 42)); do
((cnt++))
echo "$cnt" > cntfile.txt
# >& is deprecated
source myrand > error.txt 2>&1
done
)
cnt=$(<cntfile.txt)
cat error.txt
echo "$cnt"
Reference Bash manual command grouping.
As KamilCuk pointed out correctly, you should use $n instead of n.
Furthermore, I personally would add that using source ./rand.sh &> error.txt is kind of weird in this case. If you want to run it as a background process, use:
./rand.sh &> error.txt &
wait $! # $! is the pid
Otherwise, just make a function out of it:
#!/bin/bash
function myrand {
n=$(( RANDOM % 100 ))
if [[ n -eq 42 ]]; then
echo "Something went wrong"
>&2 echo "The error was using magic numbers"
return 1
fi
echo "Everything went accrding to plan"
return 0
}
cnt=0
while [[ "${n}" -ne 42 ]]
do
(( cnt = "${cnt}"+1 ))
myrand() &> error.txt
done
cat error.txt
echo "${cnt}"
p.s. code not tested, but I guess it works.

why does grep works when used as a variable and does not when used as a function in linux shell script?

I am trying to use grep as a variable and a function in a bash shell script. I get the desired output when grep is used as an variable. I do not get the desired output when grep is used as an function.
The script used for grep as a variable is as below:
#! /bin/bash
grep=$(grep -ico "mmshutdown: Finished" mmshutdown-output.txt)
#grep()
#{
# grep -ico "mmshutdown: Finished" mmshutdown-output.txt
#}
status()
{
echo $?
}
if [[ "grep" -gt "0" ]];
then
echo
echo "exit code of search mmshutdown: Finished is $(status)"
echo
echo "FILE SYSTEM UNMOUNTED SUCESSFULLY"
sleep 3
else
echo "exit code of search mmshutdown: Finished is $(status)"
echo "check output log file mmshutdown.txt"
sleep 3
fi
the out put when we run the script is
[root#ad ~]# ./grep-variable.sh
exit code of search mmshutdown: Finished is 0
FILE SYSTEM UNMOUNTED SUCESSFULLY
The script used for grep in function is as below:
#! /bin/bash
#grep=$(grep -ico "mmshutdown: Finished" mmshutdown-output.txt)
grep()
{
grep -ico "mmshutdown: Finished" mmshutdown-output.txt
}
status()
{
echo $?
}
if [[ "grep" -gt "0" ]];
then
echo
echo "exit code of search mmshutdown: Finished is $(status)"
echo
echo "FILE SYSTEM UNMOUNTED SUCESSFULLY"
sleep 3
else
echo "exit code of search mmshutdown: Finished is $(status)"
echo "check output log file mmshutdown.txt"
sleep 3
fi
the out put when we run the script is
[root#ad ~]# ./grep-function.sh
exit code of search mmshutdown: Finished is 1
check output log file mmshutdown.txt
Could someone point out what has gone wrong here? Why is grep when used as function not providing desired output?
Your both programs are comparing "grep" with "0" not the output of the grep command.
Also -c option returns the number of lines matched.
Check the following code it works with grep as function. But as grep is as a function you will need to call original grep i.e. command with complete path else it will go in an infinite loop.
Send output to /dev/null and process on command execution status.
#! /bin/bash
set -x
#grep=$(grep -ico "mmshutdown: Finished" mmshutdown-output.txt)
grep()
{
return $(/bin/grep -ico "mmshutdown: Finished" mmshutdown-output.txt > /dev/null)
}
status()
{
echo $?
}
if grep;
then
echo
echo "exit code of search mmshutdown: Finished is $(status)"
echo
echo "FILE SYSTEM UNMOUNTED SUCESSFULLY"
sleep 3
else
echo "exit code of search mmshutdown: Finished is $(status)"
echo "check output log file mmshutdown.txt"
sleep 3
fi

Bash get last line (combined) from stdout

I have a script that performs many different operations and displays the status of their completion in a clear way for the user. I need a function so that some strings can be retrieved as variables for further processing.
This is a highly simplified example:
#!/bin/bash
echo "Test script."
echo -n "1) cat file "
cat ./testfile.f &> /dev/null
if [ $? -eq 0 ]
then
echo "$(tput hpa $(tput cols))$(tput cub 8)[OK]"
else
echo "$(tput hpa $(tput cols))$(tput cub 8)[FAIL]"
fi
echo -n "2) make subfolder "
mkdir ./testdir &> /dev/null
if [ $? -eq 0 ]
then
echo "$(tput hpa $(tput cols))$(tput cub 8)[OK]"
else
echo "$(tput hpa $(tput cols))$(tput cub 8)[FAIL]"
fi
It take some as:
$./test.sh
Test script.
1) cat file [FAIL]
2) make subfolder [OK]
How can I get the last line (ideally, any string) during script execution? Ideally it would be using a function (so I could work with the resulting string) This string will be processed in the same script.
So far, I see only one solution: redirect the output of each echo command using tee.
Is there any way to read the already outputted data!?
Suppose that you have strings {1..5} that you need to process:
process() {
while read -r input; do
sleep 2
echo "Processed ${input}."
done
}
printf "line %s\n" {1..5} | process
In this situation you might want to see the numbers before they are being processed.
You can do this by duplicating stdout to fd 3 and use a function.
display() {
while read -r input; do
echo "=== ${input} ===" >&3
echo "${input}"
done
}
process() {
while read -r input; do
sleep 2
echo "Processed ${input}."
done
}
exec 3>&1
printf "line %s\n" {1..5} | display | process

circular IO redirection

I have a process I start on my shell that prints out data and I have a python script that calculates it and should return that to the process. How can I do that?
I know using pipe or > could help me with one side, but how can I achieve a two-way redirection?
Is something like: my_process | my_script | my_process legal?
What I want to happen:
start process from shell
process sends data to my script (instead of printing it to STDOUT)
my script returns an answer to process (instead of printing it to
STDOUT)
return to step 2
It's emulatable with FIFOs (or if you're using python, you can create your own pipes with the pipe system call and redirect them according to your arrangement).
Some example code:
#!/bin/sh
#note: the resource management and error handling here is not very clean or robust
mkfifo fifo0 fifo1
exec 3<>fifo0
exec 4<>fifo1
rm -f fifo0 fifo1
many()
{
i=0
while [ $i -lt $1 ]; do
echo -n x
i=$((i+1))
done
echo
}
proc1()
{
ulimit_p=$(ulimit -p)
while :; do
echo proc1_msg
echo >&2 proc1_written=proc1_msg
read var
echo >&2 proc1_read=$var
sleep 1
done
}
proc2()
{
while :; do
read var
echo >&2 proc2_read=$var
echo proc2_msg
echo >&2 proc2_written=proc2_msg
done
}
pid=0
trap 'echo kill $pid; kill $pid; exit 130' INT
proc1 <&3 >&4 & pid=$!
proc2 <&4 >&3

BASH functions inside echo strings

I feel like an idiot. I want a BASH function that alternates values every time it's called. The script itself is very simple, and it works if I call the function directly. But it doesn't work the same when called inside a string. Here's the code:
odd_or_even()
{
if [ $ODDEVEN -eq 1 ]; then
echo "odd"
let "ODDEVEN+=1"
else
echo "even"
let "ODDEVEN-=1"
fi
}
ODDEVEN=1
odd_or_even # Prints "odd"
odd_or_even # Prints "even"
echo "<td class=\"`odd_or_even`\">Test</td>" # Prints class=odd
echo "<td class=\"`odd_or_even`\">Test</td>" # Prints class=odd
Does BASH have restrictions about calling functions inside strings? It seems to work because it's outputting something, but it's not performing the mathematical operation.
The back quotes create sub-shells and the environment is reset in each sub-shell so you don't actually modify the same variable ODDEVEN.
You can use a file:
odd_or_even()
{
ODDEVEN=$(cat oddfile)
if [ $ODDEVEN -eq 1 ]; then
echo "odd"
let "ODDEVEN=0"
else
echo "even"
let "ODDEVEN=1"
fi
echo $ODDEVEN > oddfile
}
Or let the function do the string manipulation:
odd_or_even()
{
prefix=$1
suffix=$2
if [ $ODDEVEN -eq 1 ]; then
out="odd"
let "ODDEVEN=0"
else
out="even"
let "ODDEVEN=1"
fi
echo $prefix$out$suffix
}
ODDEVEN=1
odd_or_even "<td class=\"" "\">Test</td>"
odd_or_even "<td class=\"" "\">Test</td>"
Perhaps not the most elegant solution around, but you could use file descriptors since they get inherited by child processes (such as subshells).
As already pointed out, variable assignments (such as your let "ODDEVEN+=1" or let "ODDEVEN-=1") in a (backticked) subshell (child process) are not visible to the parent shell (parent process).
odd_or_even()
{
if [ $ODDEVEN -eq 1 ]; then
#echo "odd"
exec 3<&-
exec 3<<<"odd"
let "ODDEVEN+=1"
else
#echo "even"
exec 3<&-
exec 3<<<"even"
let "ODDEVEN-=1"
fi
}
export -f odd_or_even
{
ODDEVEN=1
odd_or_even && cat <&3 3<&- # Prints "odd"
odd_or_even && cat <&3 3<&- # Prints "even"
odd_or_even
echo "<td class=\"`cat <&3 3<&-`\">Test</td>" # Prints class=odd
odd_or_even
echo "<td class=\"`cat <&3 3<&-`\">Test</td>" # Prints class=odd
}
# output:
# odd
# even
# <td class="odd">Test</td>
# <td class="even">Test</td>
The goal in cases like this is to get the function out of the subshell.
function odd_or_even {
case $oddeven in
?([01]))
typeset -a strings=(even odd)
printf %s "${strings[oddeven^=1]}"
;;
*) return 1
esac
}
odd_or_even > >(echo "${prefix}$(</dev/fd/0)${suffix}") || exit
Since you're assigning to a nonlocal variable anyway there isn't really any point in not just using it directly instead of worring about I/O. This keeps both halves out of a subshell.
oddeven=
typeset -a strings=(even odd)
echo "${prefix}${strings[oddeven^=1]}${suffix}"
Your original solution is only possible in ksh93t and mksh R41 or greater using a special command substitution form that doesn't create a subshell.
function odd_or_even {
...
}
print -r -- "${prefix}${ odd_or_even;}${suffix}"
As an aside, Stop using backticks!

Resources