Question

I feel this is probably something that is fairly easy to do, I have googled it and searched the questions here, but I can't find it. Maybe this is because I am not asking the right question.

I want to take the numerical value of a variable from a netcdf file and use it in a mathematical operation in my bash script. I have tried:

 a=5*"./myfile.nc"
 a=5*./myfile.nc
 echo $a

I am getting, in both cases:

 ./myfile.nc: Permission denied
 1*/home/cohara/RainfallData/rainfall_increase/5%over10years.nc

ncdump prints all the information contained in the file to the terminal, but how do I select the variable I want, for use in the script?

Here is the ncdump output. It is the value of var61 that I want to extract:

{
    dimensions:
    lon = 1 ;
    lat = 1 ;
    height = 1 ;
    time = UNLIMITED ; // (1 currently)
variables:
    double lon(lon) ;
        lon:standard_name = "longitude" ;
        lon:long_name = "longitude" ;
        lon:units = "degrees_east" ;
        lon:axis = "X" ;
    double lat(lat) ;
        lat:standard_name = "latitude" ;
        lat:long_name = "latitude" ;
        lat:units = "degrees_north" ;
        lat:axis = "Y" ;
    double height(height) ;
        height:standard_name = "height" ;
        height:long_name = "height" ;
        height:units = "m" ;
        height:positive = "up" ;
        height:axis = "Z" ;
    double time(time) ;
        time:standard_name = "time" ;
        time:units = "year as %Y.%f" ;
        time:calendar = "proleptic_gregorian" ;
    float var61(time, height, lat, lon) ;
        var61:table = 1 ;
        var61:_FillValue = -9.e+33f ;

// global attributes:
        :CDI = "Climate Data Interface version 1.5.5 (http://code.zmaw.de/projects/cdi)" ;
        :Conventions = "CF-1.0" ;
        :history = "Tue Apr 08 12:40:41 2014: cdo divc,10 /home/cohara/RainfallData/rainfall_increase/historical_5%.nc /home/cohara/RainfallData/rainfall_increase/5%in10parts.nc\n",
            "Tue Apr 08 12:40:41 2014: cdo mulc,5 /home/cohara/RainfallData/rainfall_increase/historical_1%.nc /home/cohara/RainfallData/rainfall_increase/historical_5%.nc\n",
            "Tue Apr 08 12:40:41 2014: cdo divc,100 /home/cohara/RainfallData/rainfall_increase/historical_mean.nc /home/cohara/RainfallData/rainfall_increase/historical_1%.nc\n",
            "Tue Apr 08 12:40:41 2014: cdo timmean /home/cohara/RainfallData/rainfall_increase/historical.nc /home/cohara/RainfallData/rainfall_increase/historical_mean.nc\n",
            "Fri Mar 21 10:16:32 2014: cdo splityear ./1981-2076.nc ./1981-2076_\n",
            "Tue Mar 04 14:18:04 2014: cdo settaxis,1981-01-01,00:00:00,1year ./RainfallData/timsum_1981.nc ./RainfallData/settaxis.nc\n",
            "Tue Mar 04 13:55:00 2014: cdo timsum /home/cohara/RainfallData/fldmean_1981.nc /home/cohara/RainfallData/timsum_1981.nc\n",
            "Tue Mar 04 13:45:48 2014: cdo fldmean /home/cohara/RainfallData/corrected_precip_1981.nc /home/cohara/RainfallData/fldmean_1981.nc\n",
            "Tue Mar 04 13:43:26 2014: cdo divc,10 /home/cohara/RainfallData/PRECIP_1981.nc /home/cohara/RainfallData/corrected_precip_1981.nc\n",
            "Mon Jul 15 13:16:49 2013: cdo cat WD2_1981m10grid.csv.nc WD2_1981m11grid.csv.nc WD2_1981m12grid.csv.nc WD2_1981m1grid.csv.nc WD2_1981m2grid.csv.nc WD2_1981m3grid.csv.nc WD2_1981m4grid.csv.nc WD2_1981m5grid.csv.nc WD2_1981m6grid.csv.nc WD2_1981m7grid.csv.nc WD2_1981m8grid.csv.nc WD2_1981m9grid.csv.nc PRECIP_1981.nc\n",
            "Fri Jul 12 09:11:31 2013: cdo -f nc copy WD2_1981m10grid.csv.grb WD2_1981m10grid.csv.nc" ;
        :CDO = "Climate Data Operators version 1.5.5 (http://code.zmaw.de/projects/cdo)" ;
data:

 lon = 0 ;

 lat = 0 ;

 height = 0 ;

 time = 2012 ;

 var61 =
  5.293939 ;
}

Thanks in advance for any help.

Ciara

Was it helpful?

Solution

Try this:

a=$(ncdump myfile.nc | grep "var61:_FillValue" | sed -e "s/.*= //;s/ .*//")

explanation:

  • the pipe | sends the output from one program to the input of the other.
  • grep deletes every line that does not match the given string
  • sed does some regexp magic, it has two parts separated by ";"
    • first part matches everything up to "= " and replaces with nothing
    • second part matches everything from " " and replaces with nothing

I don't have a proper netcdf file to test right now, but it might become easier using something with ncdump -v var61 myfile.nc.

edit If you want the answer to be 5.293939, use

a=$(ncdump myfile.nc |sed -z -e "s/.* var61 =\n  //;s/ .*//")

I think I searched for the wrong value above.

Alternative:

a=$(ncdump myfile.nc |awk '/var61 =/ {nextline=NR+1}{if(NR==nextline){print $1}}')

It works like this:

  • statement1:
    • /var61 =/ searches for the string between the slashes
    • NR contains the line number. nextline is set to the next line number
  • statement2
    • when NR equals nextline, then
    • print the first word in the line

OTHER TIPS

I usually use the -v option on ncdump in case the file is very large as this is faster.

This should pick up the value of the variable:

myvar=`ncdump -v,var61 tm.nc | tail -n 2 | head -n 1 | awk '{print $1;}'`

I just use head and tail to chop off the netcdf file header and end as I find it easier to understand and remember!

Note this will only work with a variable that has a single value though, (which seems to be the case in your question and example file), since the tail command is picking up the last two lines. If you want to pick up the first entry of a variable array then this will require modification.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top