{"id":13408934,"url":"https://github.com/dwtkns/gdal-cheat-sheet","last_synced_at":"2026-02-03T10:31:50.765Z","repository":{"id":6602354,"uuid":"7845525","full_name":"dwtkns/gdal-cheat-sheet","owner":"dwtkns","description":"Cheat sheet for GDAL/OGR command-line tools","archived":false,"fork":false,"pushed_at":"2024-06-13T09:13:32.000Z","size":52,"stargazers_count":1208,"open_issues_count":5,"forks_count":271,"subscribers_count":71,"default_branch":"master","last_synced_at":"2025-06-23T04:35:10.120Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dwtkns.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-01-26T23:48:56.000Z","updated_at":"2025-06-21T07:51:37.000Z","dependencies_parsed_at":"2024-01-12T04:45:53.457Z","dependency_job_id":"efbef8f2-5f11-4442-996a-9147ea28df29","html_url":"https://github.com/dwtkns/gdal-cheat-sheet","commit_stats":{"total_commits":66,"total_committers":10,"mean_commits":6.6,"dds":0.303030303030303,"last_synced_commit":"8d1ddc60cb822987b7d93e43df93575ac6bcfc90"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dwtkns/gdal-cheat-sheet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwtkns%2Fgdal-cheat-sheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwtkns%2Fgdal-cheat-sheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwtkns%2Fgdal-cheat-sheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwtkns%2Fgdal-cheat-sheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dwtkns","download_url":"https://codeload.github.com/dwtkns/gdal-cheat-sheet/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwtkns%2Fgdal-cheat-sheet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29041325,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-03T10:09:22.136Z","status":"ssl_error","status_checked_at":"2026-02-03T10:09:16.814Z","response_time":96,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T20:00:56.711Z","updated_at":"2026-02-03T10:31:50.747Z","avatar_url":"https://github.com/dwtkns.png","language":null,"funding_links":[],"categories":["Resources","Others","others","Cheat sheets","GDAL of course","Tools"],"sub_categories":["Websites","Testing your code"],"readme":"Cheat sheet for GDAL/OGR command-line geodata tools\n\nVector operations\n---\n\n__Get vector information__\n\n\togrinfo -so input.shp layer-name\n\nOr, for all layers  \n\n\togrinfo -al -so input.shp\n\n__Print vector extent__\n\n\togrinfo input.shp layer-name | grep Extent\n\t\n__List vector drivers__\n\n\togr2ogr --formats\n\n__Convert between vector formats__\n\n\togr2ogr -f \"GeoJSON\" output.json input.shp\n\n__Print count of features with attributes matching a given pattern__\n\n\togrinfo input.shp layer-name | grep \"Search Pattern\" | sort | uniq -c\n\n__Read from a zip file__\n\nThis assumes that archive.zip is in the current directory. This example just extracts the file, but any ogr2ogr operation should work. It's also possible to write to existing zip files.\n\n\togr2ogr -f 'GeoJSON' dest.geojson /vsizip/archive.zip/zipped_dir/in.geojson\n\n__Clip vectors by bounding box__\n\n\togr2ogr -f \"ESRI Shapefile\" output.shp input.shp -clipsrc \u003cx_min\u003e \u003cy_min\u003e \u003cx_max\u003e \u003cy_max\u003e\n\n__Clip one vector by another__\n\n\togr2ogr -clipsrc clipping_polygon.shp output.shp input.shp\n\n__Reproject vector:__\n\n\togr2ogr output.shp -t_srs \"EPSG:4326\" input.shp\n\n__Add an index to a shapefile__\n\nAdd an index on an attribute:\n\n\togrinfo example.shp -sql \"CREATE INDEX ON example USING fieldname\"\n\nAdd a spatial index:\n\n\togrinfo example.shp -sql \"CREATE SPATIAL INDEX ON example\"\n\n__Merge features in a vector file by attribute (\"dissolve\")__\n\n\togr2ogr -f \"ESRI Shapefile\" dissolved.shp input.shp -dialect sqlite -sql \"select ST_union(Geometry),common_attribute from input GROUP BY common_attribute\"\n\t\n__Merge features (\"dissolve\") using a buffer to avoid slivers__\n\n\togr2ogr -f \"ESRI Shapefile\" dissolved.shp input.shp -dialect sqlite \\\n\t-sql \"select ST_union(ST_buffer(Geometry,0.001)),common_attribute from input GROUP BY common_attribute\"\n\n__Merge vector files:__\n\n\togr2ogr merged.shp input1.shp\n\togr2ogr -update -append merged.shp input2.shp -nln merged\n\n__Extract from a vector file based on query__\n\nTo extract features with STATENAME 'New York','New Hampshire', etc. from states.shp\n\n\togr2ogr -where 'STATENAME like \"New%\"' states_subset.shp states.shp\n\nTo extract type 'pond' from water.shp\n\n\togr2ogr -where \"type = pond\" ponds.shp water.shp\n\n__Subset \u0026 filter all shapefiles in a directory__\n\nAssumes that filename and name of layer of interest are the same...  \n\n\tbasename -s.shp *.shp | xargs -n1 -I % ogr2ogr %-subset.shp %.shp -sql \"SELECT field-one, field-two FROM '%' WHERE field-one='value-of-interest'\"\n\n__Extract data from a PostGis database to a GeoJSON file__\n\n\togr2ogr -f \"GeoJSON\" file.geojson PG:\"host=localhost dbname=database user=user password=password\" \\\n\t-sql \"SELECT * from table_name\"\n\n__Extract data from an ESRI REST API__\n\nServices that use ESRI maps are sometimes powered by a REST server that can provide data in OGR can consume. Finding the correct end point can be tricky and may take some false starts.\n\n\togr2ogr -f GeoJSON output.geojson \"http:/example.com/arcgis/rest/services/SERVICE/LAYER/MapServer/0/query?f=json\u0026returnGeometry=true\u0026etc=...\" OGRGeoJSON\n\n__Get the difference between two vector files__\n\nGiven two files that both have an id field, this will produce a vector file with the part of `file1.shp` that doesn't intersect with `file2.shp`:\n\n    ogr2ogr diff.shp file1.shp -dialect sqlite \\\n    -sql \"SELECT ST_Difference(a.Geometry, b.Geometry) AS Geometry, a.id \\\n    FROM file1 a LEFT JOIN 'file2.shp'.file2 b USING (id) WHERE a.Geometry != b.Geometry\"\n\nThis assumes that `file2.shp` and `file2.shp` are both in the current directory.\n\n__Spatial join:__\n\nA spatial join transfers properties from one vector layer to another based on a [spatial relationship](http://postgis.net/docs/manual-2.0/reference.html#Spatial_Relationships_Measurements) between the features. Fields from the join layer can be [aggregated](https://www.sqlite.org/lang_aggfunc.html) in the output.\n\nGiven a set of points (trees.shp) and a set of polygons (parks.shp) in the same directory, create a polygon layer with the geometries from parks.shp and summaries of some columns in trees.shp:\n\n    ogr2ogr -f 'ESRI Shapefile' output.shp parks.shp -dialect sqlite \\\n    -sql \"SELECT p.Geometry, p.id id, SUM(t.field1) field1_sum, AVG(t.field2) field2_avg\n    FROM parks p, 'trees.shp'.trees t WHERE ST_Contains(p.Geometry, t.Geometry) GROUP BY p.id\"\n\nNote that features that from parks.shp that don't overlap with trees.shp won't be in the new file.\n\nRaster operations\n---\n__Get raster information__\n\n\tgdalinfo input.tif\n\n__List raster drivers__\n\n\tgdal_translate --formats\n\t\n__Force creation of world file (requires libgeotiff)__\n\n\tlistgeo -tfw  mappy.tif\n\t\n__Report PROJ.4 projection info, including bounding box (requires libgeotiff)__\n\n\tlistgeo -proj4 mappy.tif\n\n__Convert between raster formats__\n\n\tgdal_translate -of \"GTiff\" input.grd output.tif\n\n__Convert 16-bit bands (Int16 or UInt16) to Byte type__  \n(Useful for Landsat 8 imagery...)\n\n\tgdal_translate -of \"GTiff\" -co \"COMPRESS=LZW\" -scale 0 65535 0 255 -ot Byte input_uint16.tif output_byte.tif\n\nYou can change '0' and '65535' to your image's actual min/max values to preserve more color variation or to apply the scaling to other band types - find that number with:\n\n\tgdalinfo -mm input.tif | grep Min/Max\n\t\n__Convert a directory of raster files of the same format to another raster format__\n\n\tbasename -s.img *.img | xargs -n1 -I % gdal_translate -of \"GTiff\" %.img %.tif\n\n__Reproject raster:__\n\n\tgdalwarp -t_srs \"EPSG:102003\" input.tif output.tif\n\t\nBe sure to add _-r bilinear_ if reprojecting elevation data to prevent funky banding artifacts.\n\n__Georeference an unprojected image with known bounding coordinates:__\n\n\tgdal_translate -of GTiff -a_ullr \u003ctop_left_lon\u003e \u003ctop_left_lat\u003e \u003cbottom_right_lon\u003e \u003cbottom_right_lat\u003e \\\n\t-a_srs EPSG:4269 input.png output.tif\n\n__Clip raster by bounding box__\n\n\tgdalwarp -te \u003cx_min\u003e \u003cy_min\u003e \u003cx_max\u003e \u003cy_max\u003e input.tif clipped_output.tif\n\t\n__Clip raster to SHP / NoData for pixels beyond polygon boundary__\n\n\tgdalwarp -dstnodata \u003cnodata_value\u003e -cutline input_polygon.shp input.tif clipped_output.tif\n\t\n__Crop raster dimensions to vector bounding box__\n\t\n\tgdalwarp -cutline cropper.shp -crop_to_cutline input.tif cropped_output.tif\n\n__Merge rasters__\n\n\tgdal_merge.py -o merged.tif input1.tif input2.tif\n\nAlternatively,\n\n\tgdalwarp input1.tif input2.tif merged.tif\n\t\nOr, to preserve nodata values:\n\n\tgdalwarp input1.tif input2.tif merged.tif -srcnodata \u003cnodata_value\u003e -dstnodata \u003cmerged_nodata_value\u003e\n\n__Stack grayscale bands into a georeferenced RGB__\n\nWhere LC81690372014137LGN00 is a Landsat 8 ID and B4, B3 and B2 correspond to R,G,B bands respectively:\n\n\tgdal_merge.py -co \"PHOTOMETRIC=RGB\" -separate LC81690372014137LGN00_B{4,3,2}.tif -o LC81690372014137LGN00_rgb.tif\n\n__Fix an RGB TIF whose bands don't know they're RGB__\n\n\tgdal_merge.py -co \"PHOTOMETRIC=RGB\" input.tif -o output_rgb.tif\n\n__Export a raster for Google Earth__\n\n\tgdal_translate -of KMLSUPEROVERLAY input.tif output.kmz -co FORMAT=JPEG\n\t\n__Raster calculation (map algebra)__\n\nAverage two rasters:\n\n\tgdal_calc.py -A input1.tif -B input2.tif --outfile=output.tif --calc=\"(A+B)/2\"\n\nAdd two rasters:\n\n\tgdal_calc.py -A input1.tif -B input2.tif --outfile=output.tif --calc=\"A+B\"\n\netc.\n\n__Create a hillshade from a DEM__\n\n\tgdaldem hillshade -of PNG input.tif hillshade.png\n\nChange light direction:\n\n\tgdaldem hillshade -of PNG -az 135 input.tif hillshade_az135.png \n\nUse correct vertical scaling in meters if input is projected in degrees\n\t\n\tgdaldem hillshade -s 111120 -of PNG input_WGS1984.tif hillshade.png\n\n__Apply color ramp to a DEM__  \nFirst, create a color-ramp.txt file:  \n_(Height, Red, Green, Blue)_\n\n\t\t0 110 220 110\n\t\t900 240 250 160\n\t\t1300 230 220 170\n\t\t1900 220 220 220\n\t\t2500 250 250 250\n\nThen apply those colors to a DEM:\n\n\tgdaldem color-relief input.tif color_ramp.txt color-relief.tif\n\n__Create slope-shading from a DEM__  \nFirst, make a slope raster from DEM:\n\n\t\tgdaldem slope input.tif slope.tif \n\nSecond, create a color-slope.txt file:  \n_(Slope angle, Red, Green, Blue)_\n\n\t0 255 255 255\n\t90 0 0 0  \n\nFinally, color the slope raster based on angles in color-slope.txt:  \n\n\tgdaldem color-relief slope.tif color-slope.txt slopeshade.tif\n\n__Resample (resize) raster__\n\n\tgdalwarp -ts \u003cwidth\u003e \u003cheight\u003e -r cubic dem.tif resampled_dem.tif\n\nEntering 0 for either width or height guesses based on current dimensions.\n\nAlternatively,\n\t\n\tgdal_translate -outsize 10% 10% -r cubic dem.tif resampled_dem.tif\n\nFor both of these, `-r cubic` specifies cubic interpolation: when resampling continuous data (like a DEM), the default nearest neighbor interpolation can result in \"stair step\" artifacts.\n\n__Burn vector into raster__\n\n\tgdal_rasterize -b 1 -i -burn -32678 -l layername input.shp input.tif\n\n__Extract polygons from raster__\n\n\tgdal_polygonize.py input.tif -f \"GeoJSON\" output.json\n\n__Create contours from DEM__\n\n\tgdal_contour -a elev -i 50 input_dem.tif output_contours.shp\n\n__Get values for a specific location in a raster__\n\n\tgdallocationinfo -xml -wgs84 input.tif \u003clon\u003e \u003clat\u003e  \n\n__Convert GRIB band to .tif__\n\t\nAssumes data for entire globe in WGS84. Be sure to specify band, or you may end up with a nonsense RGB image composed of the first three.\n\n\tgdal_translate input.grib -a_ullr -180 -90 180 90 -a_srs EPSG:4326 -b 1 output_band1.tif\n\t\n\nOther\n---\n__Convert KML points to CSV (simple)__\n\n\togr2ogr -f CSV output.csv input.kmz -lco GEOMETRY=AS_XY\n\n__Convert KML to CSV (WKT)__  \nFirst list layers in the KML file\n\n\togrinfo -so input.kml\n\nConvert the desired KML layer to CSV\n\n\togr2ogr -f CSV output.csv input.kml -sql \"select *,OGR_GEOM_WKT from some_kml_layer\"\n\n__CSV points to SHP__  \n\nGiven `input.csv`:\n\n\tlon,lat,value\n\t-81,31,13\n\t-80,32,14\n\t-81,33,15\n\nCreate a shapefile, using Spatialite functions to generate the point:\n\n\togr2ogr output.shp input.csv -dialect sqlite \\\n\t-sql \"SELECT MakePoint(CAST(lon as REAL), CAST(lat as REAL), 4326) Geometry, * FROM input\"\n\nNote the 4326, which refers to a spatial reference (in this case [`EPSG:4326`](http://epsg.io/4326)). Use the correct code for your data.\n\n__MODIS operations__\n\nFirst, download relevant .hdf tiles from the MODIS ftp site: \u003cftp://ladsftp.nascom.nasa.gov/\u003e; use the [MODIS sinusoidal grid](http://www.geohealth.ou.edu/modis_v5/modis.shtml) for reference.\n\nList MODIS Subdatasets in a given HDF (conf. the [MODIS products table](https://lpdaac.usgs.gov/products/modis_products_table/))\n\n\tgdalinfo longFileName.hdf | grep SUBDATASET\n\nMake TIFs from each file in list; replace 'MOD12Q1:Land_Cover_Type_1' with desired Subdataset name\n\n\tmkdir output\n\tfind . '*.hdf' -exec gdalwarp -of GTiff 'HDF4_EOS:EOS_GRID:\"{}\":MOD12Q1:Land_Cover_Type_1' output/{}.tif \\;\n\nMerge all .tifs in output directory into single file\n\n\tgdal_merge.py -o output/Merged_Landcover.tif output/*.tif\n\n__BASH functions__  \n_Size Functions_  \nThis size function echos the pixel dimensions of a given file in the format expected by gdalwarp.\n\n\tfunction gdal_size() {\n\t\tSIZE=$(gdalinfo $1 |\\\n\t\t\tgrep 'Size is ' |\\\n\t\t\tcut -d\\   -f3-4 |\\\n\t\t\tsed 's/,//g')\n\t\techo -n \"$SIZE\"\n\t}\n\nThis can be used to easily resample one raster to the dimensions of another:\n\n\tgdalwarp -ts $(gdal_size bigraster.tif) -r cubicspline smallraster.tif resampled_smallraster.tif\n\n_Extent Functions_  \nThese extent functions echo the extent of the given file in the order/format expected by gdal_translate -projwin.\n(Originally from [Linfiniti](http://linfiniti.com/2009/09/clipping-rasters-with-gdal-using-polygons/)).\n\n\tfunction gdal_extent() {\n\t\tif [ -z \"$1\" ]; then \n\t\t\techo \"Missing arguments. Syntax:\"\n\t\t\techo \"  gdal_extent \u003cinput_raster\u003e\"\n\t    \treturn\n\t\tfi\n\t\tEXTENT=$(gdalinfo $1 |\\\n\t\t\tgrep \"Upper Left\\|Lower Right\" |\\\n\t\t\tsed \"s/Upper Left  //g;s/Lower Right //g;s/).*//g\" |\\\n\t\t\ttr \"\\n\" \" \" |\\\n\t\t\tsed 's/ *$//g' |\\\n\t\t\ttr -d \"[(,]\")\n\t\techo -n \"$EXTENT\"\n\t}\n\n\tfunction ogr_extent() {\n\t\tif [ -z \"$1\" ]; then \n\t\t\techo \"Missing arguments. Syntax:\"\n\t\t\techo \"  ogr_extent \u003cinput_vector\u003e\"\n\t    \treturn\n\t\tfi\n\t\tEXTENT=$(ogrinfo -al -so $1 |\\\n\t\t\tgrep Extent |\\\n\t\t\tsed 's/Extent: //g' |\\\n\t\t\tsed 's/(//g' |\\\n\t\t\tsed 's/)//g' |\\\n\t\t\tsed 's/ - /, /g')\n\t\tEXTENT=`echo $EXTENT | awk -F ',' '{print $1 \" \" $4 \" \" $3 \" \" $2}'`\n\t\techo -n \"$EXTENT\"\n\t}\n\n\tfunction ogr_layer_extent() {\n\t\tif [ -z \"$2\" ]; then \n\t\t\techo \"Missing arguments. Syntax:\"\n\t\t\techo \"  ogr_extent \u003cinput_vector\u003e \u003clayer_name\u003e\"\n\t    \treturn\n\t\tfi\n\t\tEXTENT=$(ogrinfo -so $1 $2 |\\\n\t\t\tgrep Extent |\\\n\t\t\tsed 's/Extent: //g' |\\\n\t\t\tsed 's/(//g' |\\\n\t\t\tsed 's/)//g' |\\\n\t\t\tsed 's/ - /, /g')\n\t\tEXTENT=`echo $EXTENT | awk -F ',' '{print $1 \" \" $4 \" \" $3 \" \" $2}'`\n\t\techo -n \"$EXTENT\"\n\t}\n\nExtents can be passed directly into a gdal_translate command like so:\n\n\tgdal_translate -projwin $(ogr_extent boundingbox.shp) input.tif clipped_output.tif\n\t\nor\n\t\n\tgdal_translate -projwin $(gdal_extent target_crop.tif) input.tif clipped_output.tif\n\nThis can be a useful way to quickly crop one raster to the same extent as another. Add these to your ~/.bash_profile file for easy terminal access.\n\n\nSources\n---\n\n\u003chttp://live.osgeo.org/en/quickstart/gdal_quickstart.html\u003e\n\n\u003chttps://github.com/nvkelso/geo-how-to/wiki/OGR-to-reproject,-modify-Shapefiles\u003e  \n\n\u003cftp://ftp.remotesensing.org/gdal/presentations/OpenSource_Weds_Andre_CUGOS.pdf\u003e  \n\n\u003chttp://developmentseed.org/blog/2009/jul/30/using-open-source-tools-make-elevation-maps-afghanistan-and-pakistan/\u003e  \n\n\u003chttp://linfiniti.com/2010/12/a-workflow-for-creating-beautiful-relief-shaded-dems-using-gdal/\u003e  \n\n\u003chttp://linfiniti.com/2009/09/clipping-rasters-with-gdal-using-polygons/\u003e  \n\n\u003chttp://nautilus.baruch.sc.edu/twiki_dmcc/bin/view/Main/OGR_example\u003e  \n\n\u003chttp://www.gdal.org/frmt_hdf4.html\u003e\n\n\u003chttp://planetflux.adamwilson.us/2010/06/modis-processing-with-r-gdal-and-nco.html\u003e\n\n\u003chttp://trac.osgeo.org/gdal/wiki/FAQRaster\u003e\n\n\u003chttp://www.mikejcorey.com/wordpress/2011/02/05/tutorial-create-beautiful-hillshade-maps-from-digital-elevation-models-with-gdal-and-mapnik/\u003e\n\n\u003chttp://dirkraffel.com/2011/07/05/best-way-to-merge-color-relief-with-shaded-relief-map/\u003e\n\n\u003chttp://gfoss.blogspot.com/2008/06/gdal-raster-data-tips-and-tricks.html\u003e\n\n\u003chttp://osgeo-org.1560.x6.nabble.com/gdal-dev-Dissolve-shapefile-using-GDAL-OGR-td5036930.html\u003e\n\n\u003chttps://www.mapbox.com/tilemill/docs/guides/terrain-data/\u003e\n\n\u003chttps://gist.github.com/ashaw/0862ec044c45b9aa3c76\u003e\n\n\u003chttps://github.com/gina-alaska/dans-gdal-scripts\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdwtkns%2Fgdal-cheat-sheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdwtkns%2Fgdal-cheat-sheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdwtkns%2Fgdal-cheat-sheet/lists"}