Bash script counting instances of itself wrongly
Finally found a way, albeit an ugly one, partially inspired from the question @TomFenech linked in his answer:
#!/bin/bash
nb=$(ps f | grep '[c]ount_itself.sh' | grep -v ' \\_')
echo "$nb"
sleep 20
Execution :
root@myserver:/# ./count_itself.sh
17725 pts/1 S+ 0:00 \_ /bin/bash ./count_itself.sh
Execution with one already running in bg :
root@myserver:/# ./count_itself.sh &
[1] 17733
root@myserver:/# ./count_itself.sh
17733 pts/1 S 0:00 \_ /bin/bash ./count_itself.sh
17739 pts/1 S+ 0:00 \_ /bin/bash ./count_itself.sh
Explanation (from what I've understood) :
ps f
returns the tree of active processesgrep '[c]ount_itself.sh'
restricts the previous command to only showing instances ofcount_itself.sh
Returns
17808 pts/1 S+ 0:00 \_ /bin/bash ./count_itself.sh
17809 pts/1 S+ 0:00 \_ /bin/bash ./count_itself.sh
grep -v ' \\_'
excludes rows containing 4 spaces (equivalent of a tab) then\_
, which correspond to subprocesses
bash: differing newline count when assigning result to variable
Command substitution itself runs in a subshell so thats one
bash
processyour search for
bash
($0
) i.e.grep -c bash
also ends up in the process table at that time so thats another process (grep
) containing stringbash
. Note that, this might not show up in the process table at the time of running, depending on how busy your system is.And you have two (or whatever) actual
bash
processes (sessions) running presumably are the rest
You can use a Regex trick to get rid of the false positive i.e. grep
one from count:
ps ax | grep -c "[b]ash"
It would still count the subshell while doing command substitution:
var=$(ps ax | grep -c "[b]ash")
So you need to manually remove one from this count.
Example:
$ var=$(ps ax | grep -c "bash")
$ echo $var
4
$ var=$(ps ax | grep -c "[b]ash")
$ echo $var
3
Bash script that kills other instances of itself if they're running
Here's the basis
kill_others() {
local mypid=$$ # capture this run's pid
declare pids=($(pgrep -f ${0##*/} # get all the pids running this script
for pid in ${pids[@]/$mypid/}; do # cycle through all pids except this one
kill $pid # kill the other pids
sleep 1 # give time to complete
done
}
declare -i count=0
while [[ $(pgrep -f ${0##*/}|wc -l) -gt 1 ]]; do
kill_outhers
((++count))
if [[ $count -gt 10 ]]; then
echo "ERROR: can't kill pids" >&2
exit 1
fi
done
Counter increment in Bash loop not working
First, you are not increasing the counter. Changing COUNTER=$((COUNTER))
into COUNTER=$((COUNTER + 1))
or COUNTER=$[COUNTER + 1]
will increase it.
Second, it's trickier to back-propagate subshell variables to the callee as you surmise. Variables in a subshell are not available outside the subshell. These are variables local to the child process.
One way to solve it is using a temp file for storing the intermediate value:
TEMPFILE=/tmp/$$.tmp
echo 0 > $TEMPFILE
# Loop goes here
# Fetch the value and increase it
COUNTER=$[$(cat $TEMPFILE) + 1]
# Store the new value
echo $COUNTER > $TEMPFILE
# Loop done, script done, delete the file
unlink $TEMPFILE
Correctly count number of lines a bash variable
The wc
counts the number of newline chars. You can use grep -c '^'
for counting lines.
You can see the difference with:
#!/bin/bash
count_it() {
echo "Variablie contains $2: ==>$1<=="
echo -n 'grep:'; echo -n "$1" | grep -c '^'
echo -n 'wc :'; echo -n "$1" | wc -l
echo
}
VAR=''
count_it "$VAR" "empty variable"
VAR='one line'
count_it "$VAR" "one line without \n at the end"
VAR='line1
'
count_it "$VAR" "one line with \n at the end"
VAR='line1
line2'
count_it "$VAR" "two lines without \n at the end"
VAR='line1
line2
'
count_it "$VAR" "two lines with \n at the end"
what produces:
Variablie contains empty variable: ==><==
grep:0
wc : 0
Variablie contains one line without \n at the end: ==>one line<==
grep:1
wc : 0
Variablie contains one line with \n at the end: ==>line1
<==
grep:1
wc : 1
Variablie contains two lines without \n at the end: ==>line1
line2<==
grep:2
wc : 1
Variablie contains two lines with \n at the end: ==>line1
line2
<==
grep:2
wc : 2
Count occurrences of a char in a string using Bash
I would use the following awk
command:
string="text,text,text,text"
char=","
awk -F"${char}" '{print NF-1}' <<< "${string}"
I'm splitting the string by $char
and print the number of resulting fields minus 1.
If your shell does not support the <<<
operator, use echo
:
echo "${string}" | awk -F"${char}" '{print NF-1}'
Reliable way for a Bash script to get the full path to itself
Here's what I've come up with (edit: plus some tweaks provided by sfstewman, levigroker, Kyle Strand, and Rob Kennedy), that seems to mostly fit my "better" criteria:
SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
That SCRIPTPATH
line seems particularly roundabout, but we need it rather than SCRIPTPATH=`pwd`
in order to properly handle spaces and symlinks.
The inclusion of output redirection (>/dev/null 2>&1
) handles the rare(?) case where cd
might produce output that would interfere with the surrounding $( ... )
capture. (Such as cd
being overridden to also ls
a directory after switching to it.)
Note also that esoteric situations, such as executing a script that isn't coming from a file in an accessible file system at all (which is perfectly possible), is not catered to there (or in any of the other answers I've seen).
The --
after cd
and before "$0"
are in case the directory starts with a -
.
Related Topics
Installing PHPsh on Linux, Python Error
Path Environment Variable in Linux
Installing a Fully Functional Postgis 2.0 on Ubuntu Linux Geos/Gdal Issues
Cython Standalone Executable on Ubuntu
Where Are Core Files Stored in a Lxc Container
How to Upgrade a Package in Linux That Was Built from Source
Question About Epoll and Splice
How to Capture Unix 'Top' Command Output to a CSV File
Arguments Were Passed Wrong in Pthread
Jmp Unexpected Behavior in Shellcode When Next(Skipped) Instruction Is a Variable Definition
Getting Root Privileges in Ansible
Sox Batch Process Under Debian
Tensorflow Recommended System Specifications
When to Use Linux Kernel Add_Timer Vs Queue_Delayed_Work
How to Rename a Kernel Module Name Without Renaming The .Ko Passed to Insmod
Is There Any Reference Implementation of Linux File System Filter Driver