Link to home
Start Free TrialLog in
Avatar of doc_jay
doc_jay

asked on

Bash script help please with dates?

Hi,
   
    I'm working with this code in cygwin

#!/bin/bash -x
UTIL=/cygdrive/c/apps/dcm4che-2.0.25-bin/bin
INPUT=/cygdrive/c/projects/a4fill/A2_SUID
BASEDIR=/cygdrive/c/projects/a4fill
start="20140101"
end="20140102"
DATES=""
for i in $(seq 0 9999)
 do
  new=$(date -d "$start + $i days" "+%Y%m%d")
  if [[ $new -le $end ]]; then 
   DATES="$DATES $new"; 
   else break; 
  fi
done
for D in $DATES
 do
  $UTIL/dcmqr RADARCH2@10.10.50.51:104 -rStudyInstanceUID -qStudyDate=$D | grep "(0020,000D) UI #[0-9]*" | sed s/'(0020,000D) UI #[0-9]* \['// | sed s/'\] Study Instance UID'// | sed s/'] Study Instance'// | sed s/'UI'// | sed s/'U'// > $INPUT/A2_SUID
 cnt=0
 count=0
 exec 3<&0 # Save stdin to file descriptor 3.
 exec 0<$INPUT # Redirect standard input.
  while read input1 rest  # Let read split the line instead of running awk
   do
    echo "Row $count"
    ((cnt++))
    echo "Moving :" ${input1}
    $UTIL/dcmqr RADARCH2@10.10.50.51:104 -q0020000D=${input1} -cmove RADARCH4
    ((count++))
      if (( cnt == 50 )); then
       echo "Sleeping for 3 Minutes on $(date)"
       sleep 180
       cnt=0
      fi
exec 0<&3 # Restore old stdin.
done
echo "Counter:" $count # Show moved items

Open in new window


and its not getting past the 'date' function at the beginning of the script.  What I want it to do is I want to enter in a date range and then it will place that into '$D', but its having issues.  

Also, maybe there is a better way to write this entire script to make it more efficient?  I'm sure it looks very messy to everyone as I don't have very much experience.

thank you
SOLUTION
Avatar of woolmilkporc
woolmilkporc
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
PS: My day is over now, sorry! CU tomorrow!

wmp
Avatar of doc_jay
doc_jay

ASKER

Wmp,

    thanks - good catch on line 18.  'A2_SUID' is a file with multiple rows that I want to feed 'dcmqr' on line 28.  If i change the end of line 18 to simple '> $INPUT', it should create a file named 'A2_SUID' correct?

I'll add the missing 'done' between lines 18 & 19 and add the 'echo $DATES' between 15 & 16.  

I'll post back with results.

thanks!
Avatar of doc_jay

ASKER

wmp,

   So, it runs now, thanks!  On row 28, when it is feeding the 'A2_SUID' to the 'dcmqr' tool, it does so one at a time.  This is fine, but the way the script is written now, it is wanting every row that is in the 'A2_SUID' first before it performs the rest of its function which is '-cmove RADARCH4' after the {input1}.  Is there a way to give it one row of the 'A2_SUID' and then make the 'dcmqr' tool think it is done to force it to finish the '-cmove' command & then just loop through the rest of the input file with one row at a time?

  The way the 'dcmqr' tool works is that does a query with against the IP address of 10.10.50.51, then it does its '-cmove' function.  If there are 2000 or even 10,000 rows, it is going to take a long time for anything to start happening (it will ultimately do a dicom move of x-ray studies with the -cmove function).

-hope this is clear as mud.

ps. the 'A2_SUID' is created if it doesn't already exist, but it is appended instead of being overwritten.   Can we make it be overwritten or removed each time?

thanks
if you want to create it each script run, then just do a

echo "whatever" > $INPUT

at the beggining of the file, that will initialize it, and then to append lines to it

echo "Another whatever" >> $INPUT
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of doc_jay

ASKER

Thank you very much!  I appreciate all of your comments as they moved me along to sort out my issues.  :)

I ended up running this code:

#!/bin/bash
#created by
UTIL=/cygdrive/c/apps/dcm4che-3.3.3-bin/bin
INPUT=/cygdrive/c/projects/a4fill/2014/A2_SUID
BASEDIR=/cygdrive/c/projects/a4fill
cnt=0
count=0
exec 3<$0 #Save stdin to file descriptor 3.
exec 0<$INPUT # Redirect standard input.
while read input1 rest #Let read split the line instead of running awk
do
 echo "Row $count"
 ((cnt++))
 echo "Moving :" ${input1}
 $UTIL/movescu -c RADARCH2@10.10.50.51:104 -m 0020000D=${input1} --dest RADARCH4
  ((count++))
   if (( cnt == 50 )); then
    echo "Sleeping for 5 Seconds on $(date), I have moved $count exams"
    sleep 5
    cnt=0
   fi
exec 0<$3 #Restore old stdin.
done
echo "Counter:" $count # Show moved items

Open in new window


I moved the operation to 'movescu' because it only does  move instead of query + move.  It is exactly what I needed.

One question about the code above I posted.  My input file that I'm running this against has over 240,000 rows.  If for some reason I needed to stop the script, I would like to pick up where I left off.  How can I change the code to tell it 'start on row 4009' for example?  Or maybe there is a way for it to keep count and start where it leaves off?  I can always scroll up in the output of the console to see what row last echoed back.

thanks
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of doc_jay

ASKER

wmp,

   I decided to just get the input file from a MSSQL query and output it to a file.  Thanks for your input and I'll try it out soon because its just inevitable that I'll have to interrupt the script.  :)
doc_jay,

What you will have to do is implement TRAPS, so you can intercept signals that come from the OS, and act accordingly, that way you will always have control if any interruption occurs (apart from a power outage).

If you want to see some good examples, this one from Aaron Maxwell is a winner:


And in one of the traps you handle your row counters in a external file.

Also you will have to implement a locking file with your process PID to detect multiple runs of the same script, and only let one run at the same time.
Avatar of doc_jay

ASKER

wmp,

    In your answer above about using awk to start at a certain row, is there a way to have a 'start' and 'end'?  Reason being is that I was hoping to have only one input file with around 240,000 rows and multiple scripts reading that input file.

For example:
One script that would read from 1 to 20000
2nd script that would read from 20001 to 50000
START=1
END=20000
awk -v START=$START -v END=$END 'NR>=START&&NR<=END {print $1}' $INPUT

START=20001
END=50000
awk -v START=$START -v END=$END 'NR>=START&&NR<=END {print $1}' $INPUT
Avatar of doc_jay

ASKER

wmp,

   thanks for the help on this again.  It came back with an error.

'awk:  fatal:  cannot use gawk builtin 'END' as variable name

EDIT:  I changed the variable to 'ENDING' and it now works.

Also, is there a way to make the row count echo back the current row it is working on?  As of right now, it starts on say row 13677 and its first echo is 'Row 0'

here is what I am using as of now:

#!/bin/bash
UTIL=/cygdrive/c/apps/dcm4che-3.3.3-bin/bin
INPUT=/cygdrive/c/projects/a4fill/2014/A2_SUID
BASEDIR=/cygdrive/c/projects/a4fill
cnt=0
count=0
START=13677
ENDING=50000
awk -v START=$START -v ENDING=$ENDING 'NR>=START&&NR<=ENDING {print $1}' $INPUT  | while read input1  #starting at a certain row
do
 echo "Row $count"
 ((cnt++))
 echo "Moving :" ${input1}
 $UTIL/movescu -c RADARCH2@10.10.50.51:104 -m 0020000D=${input1} --dest RADARCH4
  ((count++))
   if (( cnt == 50 )); then
    echo "Sleeping for 5 Seconds on $(date), I have moved $count exams"
    sleep 5
    cnt=0
   fi
exec 0<$3 #Restore old stdin.
done
echo "Counter:" $count # Show moved items

Open in new window

Replace
 
count=0
START=13677

with

START=13677
count=$START

i. e. initialize the counter correctly.

At the end you should replace
echo "Counter: " $count # Show moved items
with
echo "Counter: " $((count-START)) # Show moved items
i. e. subtract the initial value from the final value (which is $ENDING+1) to get an exact count.

Sorry for the "END" thing, didn't think of that. In fact, I always use shorter variable names in awk, the long names were just for illustration. The version I tested was like this:

START=20
END=50
awk -v S=$START -v E=$END 'NR>=S&&NR<=E {print $1}' $INPUT
Avatar of doc_jay

ASKER

wmp,

   thanks for explanation, I've decided to do it the way you have in your last example, works out great.  Also, I can now run more than one script and read only one large input file.  In doing so, I've started to use the 'screen' utility but I can't scroll up in the buffer to read the last row that it echoed any more.

Question:
How could I write the current row its working on into an output file so that I could just open it up to refer to if I need to know what row the script is working on?

EDIT:  nevermind, looks like there are some commands for screen to use to scroll through the output.  -thanks again
Log the row count and keep displaying it on the terminal:

echo "Row $count" | tee -a outputfile

Log the entire script's output and keep displaying it on the terminal:

scriptname | tee outputfile
Avatar of doc_jay

ASKER

wmp,

   thanks!