How to execute unix command after few background jobs are completed? - unix

My c-shell code has to complete few concurrent background jobs before execution of some unix commands. However, somehow in code my background jobs never returns handle to unix commands.
i.e.
$cmd1 | tee $XD/m1.log&
$cmd2 | tee $XD/m2.log&
$cmd3 | tee $XD/m3.log&
$cmd4 | tee $XD/m4.log&
All 4 commands mentioned above generate 4 different files named $L1,$L2,$L3 and $L4 (example: setenv L1 $XD/div.txt etc.). I need to merge all of these files after removing the first line from them so have used following logic. But seems like sed command never gets executed
wait $!
echo "Job completed"
sed -i '1d' $L2
sed -i '1d' $L3
sed -i '1d' $L4
cat $L1 $L2 $L3 $L4 >> $L
Could you please help me to make then executes post background jobs?
tried
if (! -e $L4 ) then
if ( -f $L4 ) then
wait $!
echo "Job completed"
sed -i '1d' $L2
sed -i '1d' $L3
sed -i '1d' $L4
cat $L1 $L2 $L3 $L4 >> $L
endif
endif
but didn't help either.
$cmd1 | tee $XD/m1.log&
$cmd2 | tee $XD/m2.log&
$cmd3 | tee $XD/m3.log&
$cmd4 | tee $XD/m4.log&
if (! -e $L4 ) then
if ( -f $L4 ) then
wait $!
echo "Job completed"
sed -i '1d' $L2
sed -i '1d' $L3
sed -i '1d' $L4
cat $L1 $L2 $L3 $L4 >> $L
endif
endif
Expected results would be to generate $L file ($XD/final.txt), which would happen only when script will be back to 2nd half section containing sed command.

Short answer, just use:
wait
wait without any parameter wait will wait for all children processes. $! is pid of the last background process started so wait $! will wait only for process last child process.
Long answer, full script edited:
#!/bin/env tcsh
set cmd1 = 'printf header\nline11\nline12\n'
set cmd2 = 'printf header\nline21\nline22\n'
set cmd3 = 'printf header\nline31\nline32\n'
set cmd4 = 'printf header\nline41\nline42\n'
set XD = '.'
set L = "${XD}/m.log"
set L1 = "${XD}/m1.log"
set L2 = "${XD}/m2.log"
set L3 = "${XD}/m3.log"
set L4 = "${XD}/m4.log"
touch "${L}" "${L1}" "${L2}" "${L3}" "${L4}" || exit (1)
( ${cmd1}; sleep 5 ) | tee "${L1}" &
( ${cmd2}; sleep 2 ) | tee "${L2}" &
( ${cmd3}; sleep 4 ) | tee "${L3}" &
( ${cmd4}; sleep 3 ) | tee "${L4}" &
wait
echo "Job completed"
cat "${L1}" > "${L}"
sed '1d' "${L2}" >> "${L}"
sed '1d' "${L3}" >> "${L}"
sed '1d' "${L4}" >> "${L}"
exit (0)
Test:
% ./user3093942.tcsh
[1] 1542 1543
header
line11
line12
[2] 1545 1546
header
line21
line22
[3] 1548 1549
header
line31
line32
[4] 1551 1552
header
line41
line42
[4] + Done ( ${cmd4}; sleep 3 ) | tee ./m4.log
[3] + Done ( ${cmd3}; sleep 4 ) | tee ./m3.log
[2] + Done ( ${cmd2}; sleep 2 ) | tee ./m2.log
[1] + Done ( ${cmd1}; sleep 5 ) | tee ./m1.log
Job completed
% cat ./m.log
header
line11
line12
line21
line22
line31
line32
line41
line42

Related

How to pass variable to sed "$(sed -n '/110600002019/ =' tmuser.cf | tail -n 1)" 's/110600002019 /120700002019/' tmuser.cf

I want the variable to be passed as below.
a=110600002019
b=120700002019
sed "$(sed -n '/$a/ =' tmuser.cf | tail -n 1)" 's/$a /$b/' tmuser.cf
sed "$(sed -n "/$a/ =" tmuser.cf | tail -n 1) s/$a /$b/" tmuser.cf
Worked for me. I made a small test file
cat tmuser.cf
a
110600002019
b
c
120700002019
Wasn't sure about the 120700002019 so I put it in the file.
The output from the script above is
a
120700002019
b
c
120700002019
Note that you can learn a lot for debugging a problem like this by wrapping your command with
set -vx ; ... your cmnds .... ; set +vx
Doing so yielded the first clue
sed "$(sed -n '/$a/ =' tmuser.cf | tail -n 1)" 's/$a /$b/' tmuser.cf
1 >sed -n '/$a/ =' tmuser.cf
1 >tail -n 1
1 >sed '' 's/$a /$b/' tmuser.cf
sed: s/$a /$b/: cannot open [No such file or directory]
a
110600002019
b
c
120700002019
None of the variables are being replaced with their values. You need to use dbl-quotes so variables can be substituted.
And the error message
sed: s/$a /$b/: cannot open [No such file or directory]
tells us that sed thinks that s/$a /$b/ is a filename, not a command. All commands have to appear as one unbroken string to the shell that is passing them to sed, so notice how I've changed
...| tail -n 1)" 's/$a /$b/'...
to
...| tail -n 1) s/$a /$b/"....
IHTH

jq parsing date to timestamp

I have the following script:
curl -s -S 'https://bittrex.com/Api/v2.0/pub/market/GetTicks?marketName=BTC-NBT&tickInterval=thirtyMin&_=1521347400000' | jq -r '.result|.[] |[.T,.O,.H,.L,.C,.V,.BV] | #tsv | tostring | gsub("\t";",") | "(\(.))"'
This is the output:
(2018-03-17T18:30:00,0.00012575,0.00012643,0.00012563,0.00012643,383839.45768188,48.465051)
(2018-03-17T19:00:00,0.00012643,0.00012726,0.00012642,0.00012722,207757.18765437,26.30099514)
(2018-03-17T19:30:00,0.00012726,0.00012779,0.00012698,0.00012779,97387.01596624,12.4229077)
(2018-03-17T20:00:00,0.0001276,0.0001278,0.00012705,0.0001275,96850.15260027,12.33316229)
I want to replace the date with timestamp.
I can make this conversion with date in the shell
date -d '2018-03-17T18:30:00' +%s%3N
1521325800000
I want this result:
(1521325800000,0.00012575,0.00012643,0.00012563,0.00012643,383839.45768188,48.465051)
(1521327600000,0.00012643,0.00012726,0.00012642,0.00012722,207757.18765437,26.30099514)
(1521329400000,0.00012726,0.00012779,0.00012698,0.00012779,97387.01596624,12.4229077)
(1521331200000,0.0001276,0.0001278,0.00012705,0.0001275,96850.15260027,12.33316229)
This data is stored in MySQL.
Is it possible to execute the date conversion with jq or another command like awk, sed, perl in a single command line?
Here is an all-jq solution that assumes the "Z" (UTC+0) timezone.
In brief, simply replace .T by:
((.T + "Z") | fromdate | tostring + "000")
To verify this, consider:
timestamp.jq
[splits("[(),]")]
| .[1] |= ((. + "Z")|fromdate|tostring + "000") # milliseconds
| .[1:length-1]
| "(" + join(",") + ")"
Invocation
jq -rR -f timestamp.jq input.txt
Output
(1521311400000,0.00012575,0.00012643,0.00012563,0.00012643,383839.45768188,48.465051)
(1521313200000,0.00012643,0.00012726,0.00012642,0.00012722,207757.18765437,26.30099514)
(1521315000000,0.00012726,0.00012779,0.00012698,0.00012779,97387.01596624,12.4229077)
(1521316800000,0.0001276,0.0001278,0.00012705,0.0001275,96850.15260027,12.33316229)
Here is an unportable awk solution. It is not portable because it relies on the system date command; on the system I'm using, the relevant invocation looks like: date -j -f "%Y-%m-%eT%T" STRING "+%s"
awk -F, 'BEGIN{OFS=FS}
NF==0 { next }
{ sub(/\(/,"",$1);
cmd="date -j -f \"%Y-%m-%eT%T\" " $1 " +%s";
cmd | getline $1;
$1=$1 "000"; # milliseconds
printf "%s", "(";
print;
}' input.txt
Output
(1521325800000,0.00012575,0.00012643,0.00012563,0.00012643,383839.45768188,48.465051)
(1521327600000,0.00012643,0.00012726,0.00012642,0.00012722,207757.18765437,26.30099514)
(1521329400000,0.00012726,0.00012779,0.00012698,0.00012779,97387.01596624,12.4229077)
(1521331200000,0.0001276,0.0001278,0.00012705,0.0001275,96850.15260027,12.33316229)
Solution with sed :
sed -e 's/(\([^,]\+\)\(,.*\)/echo "(\$(date -d \1 +%s%3N),\2"/g' | ksh
test :
<commande_curl> | sed -e 's/(\([^,]\+\)\(,.*\)/echo "(\$(date -d \1 +%s%3N),\2"/g' | ksh
or :
<commande_curl> > results_curl.txt
cat results_curl.txt | sed -e 's/(\([^,]\+\)\(,.*\)/echo "(\$(date -d \1 +%s%3N),\2"/g' | ksh

comparing floating numbers in unix

I am facing problem in comparing big floating variables in unix
Code:
error message: syntax error on line 1 teletype
I got to know from one of the old posts in the forum this is because
"the script is trying to do a calculation with bc by echoing an expression into it. But one of the variables has an illegal number"
Below is the script which is giving the error
Code:
#! /bin/bash -xv
a=`cat abc.csv | sed '1d' | tr -s ' ' | cut -d, -f3`
echo $a
-180582621617.24
b=`sed '1d' def.csv | cut -d',' -f7 | awk '{s+=$1}END{ printf("%.2f\n",s)}'`
echo $b
-180582621617.37
Result=`echo "if($a !=$b) 1" | bc `
if [ $Result -eq 1 ]; then
echo "both values not equal"
else
echo " both values equal"
fi
But I was able to compare it when hard-coded
Code:
a=`echo "-180582621617.24,222.555,333.333" | awk -F"," '{print $1}'`
b=`echo "-180582621617.24,222.555,333.333" | awk -F"," '{print $1}'`
Result=`echo "if($a !=$b) 1" | bc `
if [ $Result -eq 1 ]; then
echo "both values not equal"
else
echo " both values equal"
fi
Your test in bc is return 1 if true and nothing when false.
$Result will be then either undefined or numeric (1). test with -eq only works with two operands both numeric. Just return 0 for the else case
Result=`echo "if($a !=$b) 1 else 0" | bc `
if [ $Result -eq 1 ] ; then
echo "both values not equal"
else
echo " both values equal"
fi
Use bc for dealing with floating numbers in shell:
$ bc <<< '-180582621617.24 == -180582621617.37'
0
$ bc <<< '-180582621617.24 != -180582621617.37'
1
In your case, it is going to be bc <<< "$a != $b", e.g.:
[[ bc <<< "$a != $b" ]] && Result=1 || Result=0
Thanks for all the suggestions.
I was able to compare by creating two temp files and using the diff -w command.
#! /bin/bash -xv
rm -f triger_cksum.txt data_cksum.txt
a=`cat ab.csv | sed '1d' | tr -s ' ' | cut -d, -f3`
echo $a > triger_cksum.txt
b=`sed '1d' cd.csv | cut -d',' -f61 | awk '{s+=$1}END{ printf("%.6f\n",s)}'`
echo $b > data_cksum.txt
diff_files=`diff -w triger_cksum.txt data_cksum.txt | wc -l | tr -s ' '`
if [ $diff_files -eq 0 ]
then
echo "cksum equal"
else
echo "cksum not equal"
fi

cygwin help trimming output

ping google.com -n 10 | grep Minimum | sed s/^\ \ \ \ //
will output:
Minimum = 29ms, Maximum = 49ms, Average = 32ms
I want to trim from the space after the = to the the , in Minimum
So then it would only show:
29ms
One way using awk:
ping google.com -n 10 | awk '/Minimum =/ { sub(",","",$3); print $3 }'
$ echo "Minimum = 29ms, Maximum = 49ms, Average = 32ms" | awk '{print $3}' | sed s/,//
29ms
So this should work, but might not be the most elegant expression of your requirement.
ping google.com -n 10 | grep Minimum | awk '{print $3}' | sed s/,//
You could also use cut instead of awk.

saving stdout, stderr and both into 3 separate files

I am using ksh. On this link http://www.shelldorado.com/shelltips/advanced.html#redir , there is an example for saving stdout, stderr and both into 3 separate files.
((./program 2>&1 1>&3 | tee ~/err.txt) 3>&1 1>&2 | tee ~/out.txt) > ~/mix.txt 2>&1
I tried that but I am getting below error:
ksh: syntax error: `(' unexpected
Please advice.
Pretty much works for me:
$ ksh
$ ps | grep "$$"
6987 pts/6 00:00:00 ksh
$ cat program.sh
#!/bin/sh
echo "err" 1>&2
echo "out"
$ ((./program.sh 2>&1 1>&3 | tee err.txt) 3>&1 1>&2 | tee out.txt) > mix.txt 2>&1
$ cat out.txt
out
$ cat err.txt
err
$ cat mix.txt
err
out

Resources