commandline outside of while loop works, but inside not in bash - linux

I'm working on a function which is intended to analyse result of executing emerge --pretend $package, and set USE flag in make.conf, and then execute emerge $package. Example code as below, at line 5, emerge --pretend worked fine, but at line 13, I got an error emerge: command not found.
Even if I removed the parenthesis between line 8 and line 15, nothing changed, same error, any idea? If replacing emerge with echo, same error, echo: command not found. It seemed both outside and inside of while loop are not at the same shell. Why and how to solve that?
Thank you very much!
1 #/bin/bash
2 function emgRecursion() {
3 local result
4 local str
5 result="$(emerge --pretend "="$1 | grep "\[ebuild")"
6 while read -r line
7 do (
8 if [[ $line = *"USE=\""* ]]; then
9 echo "====="
10 else
11 str="${line#*"] "}"
12 str="${str%%" "*}"
13            emerge --pretend "="$str
14 fi
15 ) </dev/tty
16 done <<<"$result"
17 }
18 emgRecursion "sys-cluster/ceph-0.94.4"

Related

Bash script : $x=$x+2 is not getting recognised

When I am executing the below script, I am getting the following error :-
The script executes infintely and below line is printed everytime.
"line 9: 1=1+2: command not found". Why?
#!/bin/bash
echo "Script 1 - Linux Scripting Book"
x=1
while [ $x -le 45 ]
do
echo x : $x
$x=$x+2
done
echo "End Of Script 1"
exit 0
Also if I change the $x=$x+2 to x+$x+2 then also I am getting the below error.
line 6: [: 1+2: integer expression expected
Same script when executed like this runs fine.
#!/bin/bash
echo "Script 1 - Linux Scripting Book"
x=1
while [ $x -le 45 ]
do
echo x : $x
let x=x+2
done
echo "End Of Script 1"
exit 0
You get line 9: 1=1+2: command not found because 1=1+2 is what $x=$x+2 is expanded into.
Use expr or let or ((...)) for integer calculations and bc for floating point:
let x=x+2
((x=x+2)) #same as above
((x+=2)) #same
((x++)) #if adding just one
((++x)) #if adding just one
x=$((x+2))
x=`expr $x + 2` #space before and after +
x=$(echo $x+2|bc) #using bc
x=$(echo $x+2.1|bc) #bc also works with floating points (numbers with decimals)
Since this part of the question isn't cleared yet, and not fine to post in a comment, I add this partial answer:
x=1; for i in 1 2 3 ; do x=$x+2; echo $x; done
1+2
1+2+2
1+2+2+2
As a side note: Don't use exit 0 at the end of your script without a good reason. When the script is done, it exits by itself without your help. The exit status will be the exit status of the last command performed, in your case a simple echo, which will almost always succeed. In the rare cases it fails, you will probably without intention hide that failure.
If you source the script, the exit will throw you out of your running shell.
But you can rewrite your while loop like this:
x=0
while (($((x)) < 9))
do
echo x : $x
x=$x+2
done
echo $((x))
x : 0
x : 0+2
x : 0+2+2
x : 0+2+2+2
x : 0+2+2+2+2
10
Because that's not the Bourne shell syntax for setting a variable; it looks more like Perl or PHP. The $ is used for parameter expansion and is not part of the variable name. Variable assignment simply uses =, and let evaluates arithmetic expressions (much like $((expression))). Another syntax that should work is x=$((x+2)). Note that these arithmetic evaluations are a bash feature; standard unix shells might require use of external tools such as expr.

How can I detect a sequence of "hollows" (holes, lines not matching a pattern) bigger than n in a text file?

Case scenario:
$ cat Status.txt
1,connected
2,connected
3,connected
4,connected
5,connected
6,connected
7,disconnected
8,disconnected
9,disconnected
10,disconnected
11,disconnected
12,disconnected
13,disconnected
14,connected
15,connected
16,connected
17,disconnected
18,connected
19,connected
20,connected
21,disconnected
22,disconnected
23,disconnected
24,disconnected
25,disconnected
26,disconnected
27,disconnected
28,disconnected
29,disconnected
30,connected
As can be seen, there are "hollows", understanding them as lines with the "disconnected" value inside the sequence file.
I want, in fact, to detect these "holes", but it would be useful if I could set a minimum n of missing numbers in the sequence.
I.e: for ' n=5' a detectable hole would be the 7... 13 part, as there are at least 5 "disconnected" in a row on the sequence. However, the missing 17 should not be considered as detectable in this case. Again, at line 21 whe get a valid disconnection.
Something like:
$ detector Status.txt -n 5 --pattern connected
7
21
... that could be interpreted like:
- Missing more than 5 "connected" starting at 7.
- Missing more than 5 "connected" starting at 21.
I need to script this on Linux shell, so I was thinking about programing some loop, parsing strings and so on, but I feel like if this could be done by using linux shell tools and maybe some simpler programming. Is there a way?
Even when small programs like csvtool are a valid solution, some more common Linux commands (like grep, cut, awk, sed, wc... etc) could be worth for me when working with embedded devices.
#!/usr/bin/env bash
last_connected=0
min_hole_size=${1:-5} # default to 5, or take an argument from the command line
while IFS=, read -r num state; do
if [[ $state = connected ]]; then
if (( (num-last_connected) > (min_hole_size+1) )); then
echo "Found a hole running from $((last_connected + 1)) to $((num - 1))"
fi
last_connected=$num
fi
done
# Special case: Need to also handle a hole that's still open at EOF.
if [[ $state != connected ]] && (( num - last_connected > min_hole_size )); then
echo "Found a hole running from $((last_connected + 1)) to $num"
fi
...emits, given your file on stdin (./detect-holes <in.txt):
Found a hole running from 7 to 13
Found a hole running from 21 to 29
See:
BashFAQ #1 - How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?
The conditional expression -- the [[ ]] syntax used to make it safe to do string comparisons without quoting expansions.
Arithmetic comparison syntax -- valid in $(( )) in all POSIX-compliant shells; also available without the expansion side effects as (( )) as a bash extension.
This is the perfect use case for awk, since the machinery of line reading, column splitting, and matching is all built in. The only tricky bit is getting the command line argument to your script, but it's not too bad:
#!/usr/bin/env bash
awk -v window="$1" -F, '
BEGIN { if (window=="") {window = 1} }
$2=="disconnected"{if (consecutive==0){start=NR}; consecutive++}
$2!="disconnected"{if (consecutive>window){print start}; consecutive=0}
END {if (consecutive>window){print start}}'
The window value is supplied as the first command line argument; left out, it defaults to 1, which means "display the start of gaps with at least two consecutive disconnections". Probably could have a better name. You can give it 0 to include single disconnections. Sample output below. (Note that I added series of 2 disconnections at the end to test the failure that Charles metions).
njv#organon:~/tmp$ ./tst.sh 0 < status.txt # any number of disconnections
7
17
21
31
njv#organon:~/tmp$ ./tst.sh < status.txt # at least 2 disconnections
7
21
31
njv#organon:~/tmp$ ./tst.sh 8 < status.txt # at least 9 disconnections
21
Awk solution:
detector.awk script:
#!/bin/awk -f
BEGIN { FS="," }
$2 == "disconnected"{
if (f && NR-c==nr) c++;
else { f=1; c++; nr=NR }
}
$2 == "connected"{
if (f) {
if (c > n) {
printf "- Missing more than 5 \042connected\042 starting at %d.\n", nr
}
f=c=0
}
}
Usage:
awk -f detector.awk -v n=5 status.txt
The output:
- Missing more than 5 "connected" starting at 7.
- Missing more than 5 "connected" starting at 21.

I keep receiving this error message: del: line 13: syntax error: unexpected end of file

I keep receiving this error message:
del: line 13: syntax error: unexpected end of file
This is my script:
1 echo -e "Enter a filename"
2 read filename
3 if [$filename = myfirst]
4 then
5 echo -e "do you want to delete?"
6 read answer
7 if [answer= Y]
8 then rm myfirst
9 else [answer = N]
10 echo -e "file not deleted"
11 fi
12 exit0
Your if/fi syntax is not complete or closed (missing fi).
To detect such bugs prior to running your script you should always use
bash -n scriptname
This performs a syntax check detecting such problems without actually running the script.

How to fork a function with params in bash?

I'm new to bash scripting and I faced an issue when I tried to improve my script. My script is spliting a text file and each part of this text file is processed in a function ... Everything is working fine but my problem occurs when I'm forking (with &) my function processing ! My args are not like expected (it's a line number and text with whitespaces and backspaces) and I suppose it's because of global variables ... I tried to fork, then sleep 1 second in the parent thread and then continue in order to put args into local variables for my function execution but it doesn't work either ... Can you give me a hint about how to do it ? What I want is to be able to pass args to my function and be allowed to modify it after the fork call in my parent thread ... is it possible ?
Thanks in advance :)
Here is my script :
#!/bin/bash
#Parameters#
FILE='tasks'
LINE_BY_THREAD='500'
#Function definition
function checkPart() {
local NUMBER="$1"
local TXT="$2"
echo "$TXT" | { while IFS= read -r line ; do
IFS=' ' read -ra ADDR <<< "$line"
#If the countdown is set to 0, launch the task ans set it to init value
if [ ${ADDR[0]} == '0' ]; then
#task launching
#to replace by $()l
echo `./${ADDR[1]}.sh ${ADDR[2]} &`
#countdown set to init value
sed -i "$NUMBER c ${ADDR[3]} ${ADDR[1]} ${ADDR[2]} ${ADDR[3]}" $FILE
else
sed -i "$NUMBER c $((ADDR-1)) ${ADDR[1]} ${ADDR[2]} ${ADDR[3]}" $FILE
fi
((NUMBER++))
done }
}
#Init processes number#
LINE_NUMBER=$(wc -l < $FILE)
NB_PROCESSES=$(($LINE_NUMBER / $LINE_BY_THREAD))
if [ $(($LINE_NUMBER % $LINE_BY_THREAD)) -ne '0' ]; then
((NB_PROCESSES++))
fi
echo "Number of thread to be run : $NB_PROCESSES"
#Start the split sequence#
for (( i = 2; i <= $LINE_NUMBER; i += $LINE_BY_THREAD ))
do
PARAM=$(sed "$i,$(($i + $LINE_BY_THREAD - 1))!d" "$FILE")
(checkPart "$i" "$PARAM") &
sleep 1
done
My job is to create a scheduler for tasks described in this following file :
#MinutesBeforeLaunch#TypeOfProcess#Argument#Frequency#
2 agr_m 42 5
5 agr_m_s 26 5
0 agr_m 42 5
3 agr_m_s 26 5
0 agr_m 42 5
5 agr_m_s 26 5
4 agr_m 42 5
5 agr_m_s 26 5
4 agr_m 42 5
4 agr_m_s 26 5
2 agr_m 42 5
4 agr_m_s 26 5
When I'm reading a number > 0 in the first column, I just decrement it and when it's a 0 I have to launch the task and set the first number to frequency, last column ...
My first code is the previous with sed for text replacement but is it possible to do better ?

how to detect line number of output of shell script

I am using below script ,
clear
tput cup 1
echo "1";
tput cup 2
echo "2";
tput cup 4
echo "3";
then Out put is coming like
1
2
3
If i use wrong script like ,
clear
tput cup 1
echo "1";
tput cup 2
echo ;"2";
tput cup 3
echo "3";
then out put is
1
3/var.sh: line 5: 2: command not found
This means in third line 3 printed and 2 line error also printed .
So is there any way to detect error line number to print 3 after error?
EDIT:
when I use -x , output is
[root#srinivas Installation]# sh -x var.sh
+ clear
+ tput cup 1
+ echo 1
+ echo
+ echo 3up 2
3 2
[root#srinivas Installation]# found
+ tput cup 3
If you run your shell script with the -x option, it'll show you each line as it executes.
This is because standard output and standard error are printed in different ways - Standard output is synchronous, meaning the lines will be printed in sequence and as they arrive, while standard error is asynchronous, which means it's printed whenever the terminal can fit it in. One way to fix this is to chunk standard error together with standard output:
/var.sh 2>&1
More details in Greg's wiki.
PS: All the semicolons in the file are unnecessary - If your commands are separated by newlines, semicolons will never be necessary.
That output looks like what should be expected. Here's the sequence:
tput cup 1
echo "1"
Move to line 1 and output a 1. This works properly.
tput cup 2
echo ;"2";
Move to line 2, then output a blank line (echo with no arguments) which moves to line 3. Then execute a program named 2, which the script can't find, resulting in the error message ./var.sh: line 5: 2: command not found printed on line 3.
tput cup 3
echo "3";
Move to line 3 and output a 3, which overwrites the . in the above error message. Resulting in the final apparent output that you note, even though it wasn't produced in a strictly left-to-right top-to-bottom order.

Resources