Answers: <p>I used the following script on GitHub by Rodrigue Koffi (bonclay7) and it works pretty good.</p>
  
  <p><a href="https://github.com/bonclay7/aws-amicleaner" rel="noreferrer">https://github.com/bonclay7/aws-amicleaner</a></p>
  
  <p>Command:</p>
  
  <pre><code>amicleaner --check-orphans
  </code></pre>
  
  <p>From the documentation <a href="http://techblog.d2-si.eu/2017/06/15/cleaning-your-amazon-machine-images.html" rel="noreferrer">blog post</a> it does some more things:</p>
  
  <blockquote>
    <p>It actually does a bit more than that, at of today it allows:</p>
    
    <ul>
    <li>Removing a list of images and associated snapshots</li>
    <li>Mapping AMIs:
    
    <ul>
    <li>Using names</li>
    <li>Using tags</li>
    </ul></li>
    <li>Filtering AMIs:
    
    <ul>
    <li>used by running instances</li>
    <li>from autoscaling groups (launch configurations) with a desired capacity set to 0</li>
    <li>from launch configurations detached from autoscaling groups</li>
    </ul></li>
    <li>Specifying how many AMIs you want to keep</li>
    <li>Cleaning orphan snapshots</li>
    <li>A bit of reporting</li>
    </ul>
  </blockquote>
  
Answers: CC BY-SA 3.0
Answers: 2017-09-11T22:59:08.663Z
Answers: 2017-09-12T07:51:46.423Z
Answers: 2017-09-12T07:51:46.423Z
Answers: StackOverFlow User
Answers: <p>Here is one script which can help you find orphaned snapshots</p>
  
  <pre><code>comm -23 &lt;(echo $(ec2-describe-snapshots --region eu-west-1 | grep SNAPSHOT | awk '{print $2}' | sort | uniq) | tr ' ' '\n') &lt;(echo $(ec2-describe-images --region eu-west-1 | grep BLOCKDEVICEMAPPING | awk '{print $3}' | sort | uniq) | tr ' ' '\n') | tr '\n' ' '
  </code></pre>
  
  <p>(from <a href="http://www.robertsindall.co.uk/blog/how-to-clean-up-amazon-ebs-volumes-and-snapshots/" rel="nofollow noreferrer">here</a>)</p>
  
  <p>Also you can check this article from <a href="https://serverfault.com/questions/611831/find-all-snapshots-created-by-ami-where-ami-is-deleted">serverfault</a></p>
  
  <p>P.S. Of course you can change the region to reflect your</p>
  
  <p>P.P.S. Here is updated code:</p>
  
  <pre><code> comm -23 \
  &lt;(echo $(aws ec2 describe-snapshots --region eu-west-1 |awk '/SNAPSHOT/ {print $2}' | sort -u) | tr ' ' '\n') \
  &lt;(echo $(aws ec2 describe-images --region eu-west-1 |  awk '/BLOCKDEVICEMAPPING/ {print $3}' | sort -u) | tr ' ' '\n') | tr '\n' ' '
  </code></pre>
  
  <p>The sample exaplanations what the code do is:</p>
  
  <pre><code>echo $(aws ec2 describe-snapshots --region eu-west-1 | awk '/SNAPSHOT/ {print $2}' | sort -u) | tr ' ' '\n')
  </code></pre>
  
  <p>send to STDOUT the list of snapshots. this construction:</p>
  
  <pre><code>&lt;(...)
  </code></pre>
  
  <p>create virtual temporary filehandler to make <code>comm</code> command read from two "files" and compare them</p>
  
Answers: CC BY-SA 3.0
Answers: 2017-03-22T18:26:35.267Z
Answers: Did you test it? I found the same article but can't get it to work. If you can, user error on my end, but I fear it may be outdated based on the age of the article.
Answers: Alex
Answers: CC BY-SA 3.0
Answers: 2017-03-22T18:27:24.897Z
Answers: @Alex, can check it tomorrow
Answers: Romeo Ninov
Answers: CC BY-SA 3.0
Answers: 2017-03-22T18:47:12.213Z
Answers: Command see have changed, use aws ec2 describe/delete
Answers: Tensibai
Answers: CC BY-SA 3.0
Answers: 2017-03-22T18:48:45.127Z
Answers: @Tensibai, thank you. Let me confirm it tomorrow and will edit my answer :)
Answers: Romeo Ninov
Answers: CC BY-SA 3.0
Answers: 2017-03-22T18:53:33.757Z
Answers: I did found the same source, but chaining hero awk sort and uniq makes my shell coder side sad, I'll post my version tomorrow :)
Answers: Tensibai
Answers: CC BY-SA 3.0
Answers: 2017-03-22T19:18:00.503Z
Answers: I don't understand the magic in the included script. Can you think of a way to extend your answer a bit to add some explanation about it?
Answers: Pierre.Vriens
Answers: CC BY-SA 3.0
Answers: 2017-03-22T19:19:58.950Z
Answers: @Pierre.Vriens, give me time till tomorrow, will simplify and explain the script :)
Answers: Romeo Ninov
Answers: CC BY-SA 3.0
Answers: 2017-03-22T19:22:09.020Z
Answers: Fine for me, just wanted to provide you some (constructive) feedback to let you know that what probably looks like regular English to an expert (like you), looks pretty much like Chinese to me, ok? PS: and it doesn't sound Flemish either ... Drop me an extra comment if you want to notify me after you're done (if you want my updated feedback then).
Answers: Pierre.Vriens
Answers: CC BY-SA 3.0
Answers: 2017-03-23T07:34:40.757Z
Answers: @Pierre.Vriens, now you can check updated answer :)
Answers: Romeo Ninov
Answers: CC BY-SA 3.0
Answers: 2017-03-23T08:46:01.097Z
Answers: Looks like quite some progress. But IMO te PPS is confusing as related to what was in front of it already in the prior version. Why not just integrate it all without such PPS? Also, there are some typos and punctuation issues (like 'commend'?) that you may want to address, no?
Answers: Pierre.Vriens
Answers: CC BY-SA 3.0
Answers: 2017-03-22T18:11:09.197Z
Answers: 2017-03-23T08:44:06.510Z
Answers: 2017-04-13T12:14:55.217Z
Answers: Romeo Ninov
Answers: <p><a href="https://gist.github.com/daniilyar/45d3fc1867bf435d8c21e9e4864ff472" rel="nofollow noreferrer">Here</a> is a GitHub Gist code snippet of exactly what you are asking for by Daniil Yaroslavtsev. </p>
  
  <p>It uses the list of all images and their snapshots and compares the IDs to list of all snapshot IDs. Whatever remains are the orphaned ones. The code works in the same principle as the answer above, but is better formatted and slightly more readable. </p>
  
  <p>The code takes advantage of the JMESPath with
   <code>--query Snapshots[*].SnapshotId</code> option (you can also use jp command line utility for that, if its already in your distribution. The formats the output as text with <code>--output text</code>. Here is a <a href="http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-snapshots.html" rel="nofollow noreferrer">link</a> to API reference and few examples. It is slightly more elegant than a long chain of grep/awk/sort/uniq/tr pipes.</p>
  
  <p><strong>Warning by Todd Walton</strong>: Don't mistake with 'jq' utility which uses different query language to parse json documents.</p>
  
Answers: CC BY-SA 4.0
Answers: 2018-11-14T17:54:22.030Z
Answers: Just FYI, the jq command line utility is *not* the same JSON query language as what the "aws" command uses. The "aws" command uses JMESPath.
Answers: Todd Walton
Answers: CC BY-SA 4.0
Answers: 2018-11-14T18:58:27.317Z
Answers: Thank you for pointing that out. I've learned something new today.
Answers: Jiri Klouda
Answers: CC BY-SA 4.0
Answers: 2017-03-23T05:22:17.267Z
Answers: 2018-11-14T18:57:43.943Z
Answers: 2018-11-14T18:57:43.943Z
Answers: Jiri Klouda
Answers: <p>I've written <a href="https://gist.github.com/Eyjafjallajokull/4e917414cfb191391f9e51f6a8c3e46a" rel="nofollow noreferrer">snapshots.py</a> script which iterates over all snapshots (in defined list of regions) and generates <code>report.csv</code>. This file contains information about instance, AMI and volume referenced by all snapshots.</p>
  
  <p>There is also command to interactively remove dangling snapshots.</p>
  
Answers: CC BY-SA 4.0
Answers: 2019-06-30T10:56:08.590Z
Answers: 2019-06-30T10:56:08.590Z
Answers: jazgot
Answers: <p>Largely inspired by the blog posts and gist already linked in the other answers, here is my take to the problem.</p>
  
  <p>I did use some convoluted <a href="http://jmespath.org/" rel="nofollow noreferrer">JMESpath</a> functions to get a list of snapshots and not require <code>tr</code>.</p>
  
  <p><em>Disclaimer</em>: Use at your <strong>own risks</strong>, I did my best to avoid any problem and keep sane defaults, but I won't take any blame if it cause problem to you.</p>
  
  <pre class="lang-sh prettyprint-override"><code>#!/bin/sh
  # remove x if you don't want to see the commands
  set -ex
  
  # Some variable initialisation with sane defaults
  DRUN='--dry-run'
  DO_DELETE=${1:-'no'}
  REGION=${2:-'eu-west-1'}
  ACCOUNTID=${3:-'self'}
  
  # Get two temporary files
  SNAP_FILE=$(mktemp)
  IMAGE_FILE=$(mktemp)
  
  # Get the snapshot list and the volume list
  aws --region "$REGION" ec2 describe-snapshots --owner-ids "$ACCOUNTID" --query 'Snapshots[*].[SnapshotId]' --output text &gt; "$SNAP_FILE"
  aws --region "$REGION" ec2 describe-images --owners "$ACCOUNTID" --filters Name=state,Values=available --query 'Images[*].BlockDeviceMappings[*].Ebs.[SnapshotId]' --output text &gt; "$IMAGE_FILE"
  
  # Check if the outputed command should be dry-run (default) or not
  if [ "$DO_DELETE" = "IAMSURE" ]
  then
   DRUN=''
  fi
  
  # count each snapshot id, decrease when a volume reference it, print delete command for those with no volumes
  awk -v REGION="$REGION" -v DRUN="$DRUN" '
  FNR==NR { snap[$1]++; next } # increment snapshots and get to next line in file immediately
  
  { snap[$1]-- } # we changed file, decrease the snap counter when a volume reference it
  
  END {
   for (s in snap) { # loop over the snapshots
     if (snap[s] &gt; 0) { # if we did not decrese under 1 that means there is no volume referencing this snapshot
      cmd="aws --region " REGION " " DRUN " ec2 delete-snapshot --snapshot-id " s
      print(cmd)
    }
   }
  }
  ' "$SNAP_FILE" "$IMAGE_FILE"
  # Clean up the temp files
  rm "$SNAP_FILE" "$IMAGE_FILE"
  </code></pre>
  
  <p>I hope the script itself is commented enough.</p>
  
  <p>Default usage (no-params) will list delete commands of orphaned snapshots for the current account and region eu-west-1, extract:</p>
  
  <pre><code>aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-81e5856a
  aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-95c68c7e
  aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-a3bf50bd
  </code></pre>
  
  <p>You can redirect this output to a file for review before sourcing it to execute all the commands.</p>
  
  <p>If you want the script to execute the command instead of printing them, replace <code>print(cmd)</code> by <code>system(cmd)</code>.</p>
  
  <p>Usage is as follow with a script named <code>snap_cleaner</code>:</p>
  
  <p>for dry-run commands in us-west-1 region</p>
  
  <pre><code>./snap_cleaner no us-west-1
  </code></pre>
  
  <p>for usable commands in eu-central-1</p>
  
  <pre><code>./snap_cleaner IAMSURE eu-central-1 
  </code></pre>
  
  <p>A third parameter can be used to access another account (I do prefer to switch role to another account before).</p>
  
  <p>Stripped down version of the script with awk script as a oneliner:</p>
  
  <pre><code>#!/bin/sh
  set -ex
  
  # Some variable initialisation with sane defaults
  DRUN='--dry-run'
  DO_DELETE=${1:-'no'}
  REGION=${2:-'eu-west-1'}
  ACCOUNTID=${3:-'self'}
  
  # Get two temporary files
  SNAP_FILE=$(mktemp)
  IMAGE_FILE=$(mktemp)
  
  # Get the snapshot list and the volume list
  aws --region "$REGION" ec2 describe-snapshots --owner-ids "$ACCOUNTID" --query 'Snapshots[*].[SnapshotId]' --output text &gt; "$SNAP_FILE"
  aws --region "$REGION" ec2 describe-images --owners "$ACCOUNTID" --filters Name=state,Values=available --query 'Images[*].BlockDeviceMappings[*].Ebs.[SnapshotId]' --output text &gt; "$IMAGE_FILE"
  
  # Check if the outputed command should be dry-run (default) or not
  if [ "$DO_DELETE" = "IAMSURE" ]
  then
   DRUN=''
  fi
  
  # count each snapshot id, decrease when a volume reference it, print delete command for those with no volumes
  awk -v REGION="$REGION" -v DRUN="$DRUN" 'FNR==NR { snap[$1]++; next } { snap[$1]-- } END { for (s in snap) { if (snap[s] &gt; 0) { cmd="aws --region " REGION " " DRUN " ec2 delete-snapshot --snapshot-id " s; print(cmd) } } }' "$SNAP_FILE" "$IMAGE_FILE"
  # Clean up the temp files
  rm "$SNAP_FILE" "$IMAGE_FILE"
  </code></pre>
  
Answers: CC BY-SA 3.0
Answers: 2017-03-23T11:08:31.253Z
Answers: Magnific! And except from the 'follow' (which IMO should be 'follows'), I think this answer is to be considered as a sample of high quality posts. The only thing in it that seems a bit redundant, is the disclaimer (anything one uses from something on an SE site comes with "use it at your own risk"). I can only think of 1 additional improvement you might want to add: an indication if *you* did test this script and if so how to summarize its test results (something like "works as designed"?). Obviously, if you already use it yourself, that's an even better indication.
Answers: Pierre.Vriens
Answers: CC BY-SA 3.0
Answers: 2017-03-23T11:16:22.583Z
Answers: @pierre wrote it this morning , tested partially, will probably enter our pipeline this afternoon, and while I agree on the general idea ´provided as is' , the risk level of removing a ´backup' is high and I feel I should stress it even more.
Answers: Tensibai
Answers: CC BY-SA 3.0
Answers: 2017-03-23T11:24:25.997Z
Answers: Hm, so we can get you involved to start a ***free code writing service*** for these kinds of DevOps needs (with some disclaimer-strings attached) ... interesting! I suggest that later on (when time is right), you add a minor update (at the end) like "*my script entered our pipeline this afternoon*".
Answers: Pierre.Vriens
Answers: CC BY-SA 3.0
Answers: 2017-03-23T12:40:01.993Z
Answers: @Pierre.Vriens I said probably, not guarantee, could be next week or later also ;)
Answers: Tensibai
Answers: CC BY-SA 3.0
Answers: 2017-03-23T12:42:28.503Z
Answers: Better late then never, n'est-çe pas?
Answers: Pierre.Vriens
Answers: CC BY-SA 3.0
Answers: 2017-03-23T13:49:46.723Z
Answers: I get `unexpected EOF while looking for matching '` on the line with `awk -v REGION="$REGION" -v DRUN="$DRUN" '` ?
Answers: Alex
Answers: CC BY-SA 3.0
Answers: 2017-03-23T13:52:06.287Z
Answers: @Alex On which distribution ? I assume the problem comes from which shell is effectively called by `/bin/sh`. Replacing carriage returns by `;` in the awk script should fix, removing a part of readability
Answers: Tensibai
Answers: CC BY-SA 3.0
Answers: 2017-03-23T13:53:08.633Z
Answers: @Alex and just noticed I forgot a pair of {} for the commands within the `if` while copy/pasting
Answers: Tensibai
Answers: CC BY-SA 3.0
Answers: 2017-03-23T13:59:56.857Z
Answers: I'm running bash 3.2.57(1)-release - not sure which carriage returns should be changed, could you provide an edit and/or another snippet with the change?
Answers: Alex
Answers: CC BY-SA 3.0
Answers: 2017-03-23T14:03:29.443Z
Answers: @Alex Edited with a stripped version, without the comments in the awk script and as one liner
Answers: Tensibai
Answers: CC BY-SA 3.0
Answers: 2017-03-23T14:19:12.057Z
Answers: Perfect, thanks for editing! Works exactly as intended.
Answers: Alex
Answers: CC BY-SA 4.0
Answers: 2021-03-24T21:37:12.557Z
Answers: I needed a list of snapshot that was easy to check, and potentially remove some entries from, before actually deleting the stuff, as I had some manually created snapshots that I wanted to keep, even though no AMI referenced them. So I used you code as a base for a new scripts for supporting this: https://gist.github.com/Kreinoee/8d80ff8710f983cfc096be3afa641216
Answers: Anders Kreinøe
Answers: CC BY-SA 4.0
Answers: 2017-03-23T10:46:19.017Z
Answers: 2019-02-17T15:25:15.287Z
Answers: 2019-02-17T15:25:15.287Z
Answers: Tensibai
Body: <p>We end up with a fair amount of AWS EC2 snapshots where the AMI has been deleted, but the snapshot is left behind to rot. I'd like a non-manual way of <strong>identifying and deleting</strong> these orphans to save us money and space. </p>
  
  <p>Ideally I'm thinking a <strong>bash script leveraging the CLI</strong>, but my AWS-fu is weak. I assume someone's done this before but I can't find a script that actually works. </p>
  
  <p>In the best-case scenario this will also check volumes and clean those as well, but that may be better suited for a second question.</p>
  
Comments: CC BY-SA 3.0
Comments: 2017-09-05T16:11:53.917Z
Comments: [My version on python.](https://johnnybig.pw/github/how-to-clean-orphaned-ec2-snapshots/) How-to use and github link
Comments: E.Big
Tags: <amazon-web-services><amazon-ec2>
Title: How to clean up orphaned AWS EC2 snapshots?
UserDisplayName: Alex
ThreadText: # How to clean up orphaned AWS EC2 snapshots?
  
  (Asked by: username_0 on 2017-03-22)
  
  We end up with a fair amount of AWS EC2 snapshots where the AMI has been deleted, but the snapshot is left behind to rot. I'd like a non-manual way of **identifying and deleting** these orphans to save us money and space.
  
  Ideally I'm thinking a **bash script leveraging the CLI**, but my AWS-fu is weak. I assume someone's done this before but I can't find a script that actually works.
  
  In the best-case scenario this will also check volumes and clean those as well, but that may be better suited for a second question.
  
  **Tags:** amazon-web-services, amazon-ec2
  
  > **Comments:**
  > **username_1**: [My version on python.](https://johnnybig.pw/github/how-to-clean-orphaned-ec2-snapshots/) How-to use and github link  
  
  ---
  
  ## 5 answers
  
  ### Answer by username_4 on 2017-03-23. Score: 16 | Accepted answer
  
  Largely inspired by the blog posts and gist already linked in the other answers, here is my take to the problem.
  
  I did use some convoluted [JMESpath](http://jmespath.org/) functions to get a list of snapshots and not require `tr`.
  
  *Disclaimer*: Use at your **own risks**, I did my best to avoid any problem and keep sane defaults, but I won't take any blame if it cause problem to you.
  
  ```sh
  #!/bin/sh
  # remove x if you don't want to see the commands
  set -ex
  
  # Some variable initialisation with sane defaults
  DRUN='--dry-run'
  DO_DELETE=${1:-'no'}
  REGION=${2:-'eu-west-1'}
  ACCOUNTID=${3:-'self'}
  
  # Get two temporary files
  SNAP_FILE=$(mktemp)
  IMAGE_FILE=$(mktemp)
  
  # Get the snapshot list and the volume list
  aws --region "$REGION" ec2 describe-snapshots --owner-ids "$ACCOUNTID" --query 'Snapshots[*].[SnapshotId]' --output text > "$SNAP_FILE"
  aws --region "$REGION" ec2 describe-images --owners "$ACCOUNTID" --filters Name=state,Values=available --query 'Images[*].BlockDeviceMappings[*].Ebs.[SnapshotId]' --output text > "$IMAGE_FILE"
  
  # Check if the outputed command should be dry-run (default) or not
  if [ "$DO_DELETE" = "IAMSURE" ]
  then
   DRUN=''
  fi
  
  # count each snapshot id, decrease when a volume reference it, print delete command for those with no volumes
  awk -v REGION="$REGION" -v DRUN="$DRUN" '
  FNR==NR { snap[$1]++; next } # increment snapshots and get to next line in file immediately
  
  { snap[$1]-- } # we changed file, decrease the snap counter when a volume reference it
  
  END {
   for (s in snap) { # loop over the snapshots
     if (snap[s] > 0) { # if we did not decrese under 1 that means there is no volume referencing this snapshot
      cmd="aws --region " REGION " " DRUN " ec2 delete-snapshot --snapshot-id " s
      print(cmd)
    }
   }
  }
  ' "$SNAP_FILE" "$IMAGE_FILE"
  # Clean up the temp files
  rm "$SNAP_FILE" "$IMAGE_FILE"
  
  ```
  
  I hope the script itself is commented enough.
  
  Default usage (no-params) will list delete commands of orphaned snapshots for the current account and region eu-west-1, extract:
  
  ```
  aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-81e5856a
  aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-95c68c7e
  aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-a3bf50bd
  
  ```
  
  You can redirect this output to a file for review before sourcing it to execute all the commands.
  
  If you want the script to execute the command instead of printing them, replace `print(cmd)` by `system(cmd)`.
  
  Usage is as follow with a script named `snap_cleaner`:
  
  for dry-run commands in us-west-1 region
  
  ```
  ./snap_cleaner no us-west-1
  
  ```
  
  for usable commands in eu-central-1
  
  ```
  ./snap_cleaner IAMSURE eu-central-1 
  
  ```
  
  A third parameter can be used to access another account (I do prefer to switch role to another account before).
  
  Stripped down version of the script with awk script as a oneliner:
  
  ```
  #!/bin/sh
  set -ex
  
  # Some variable initialisation with sane defaults
  DRUN='--dry-run'
  DO_DELETE=${1:-'no'}
  REGION=${2:-'eu-west-1'}
  ACCOUNTID=${3:-'self'}
  
  # Get two temporary files
  SNAP_FILE=$(mktemp)
  IMAGE_FILE=$(mktemp)
  
  # Get the snapshot list and the volume list
  aws --region "$REGION" ec2 describe-snapshots --owner-ids "$ACCOUNTID" --query 'Snapshots[*].[SnapshotId]' --output text > "$SNAP_FILE"
  aws --region "$REGION" ec2 describe-images --owners "$ACCOUNTID" --filters Name=state,Values=available --query 'Images[*].BlockDeviceMappings[*].Ebs.[SnapshotId]' --output text > "$IMAGE_FILE"
  
  # Check if the outputed command should be dry-run (default) or not
  if [ "$DO_DELETE" = "IAMSURE" ]
  then
   DRUN=''
  fi
  
  # count each snapshot id, decrease when a volume reference it, print delete command for those with no volumes
  awk -v REGION="$REGION" -v DRUN="$DRUN" 'FNR==NR { snap[$1]++; next } { snap[$1]-- } END { for (s in snap) { if (snap[s] > 0) { cmd="aws --region " REGION " " DRUN " ec2 delete-snapshot --snapshot-id " s; print(cmd) } } }' "$SNAP_FILE" "$IMAGE_FILE"
  # Clean up the temp files
  rm "$SNAP_FILE" "$IMAGE_FILE"
  
  ```
  
  > **Comments:**
  > **username_5**: Magnific! And except from the 'follow' (which IMO should be 'follows'), I think this answer is to be considered as a sample of high quality posts. The only thing in it that seems a bit redundant, is the disclaimer (anything one uses from something on an SE site comes with "use it at your own risk"). I can only think of 1 additional improvement you might want to add: an indication if *you* did test this script and if so how to summarize its test results (something like "works as designed"?). Obviously, if you already use it yourself, that's an even better indication.  
  > **username_4**: @pierre wrote it this morning , tested partially, will probably enter our pipeline this afternoon, and while I agree on the general idea ´provided as is' , the risk level of removing a ´backup' is high and I feel I should stress it even more.  
  > **username_5**: Hm, so we can get you involved to start a ***free code writing service*** for these kinds of DevOps needs (with some disclaimer-strings attached) ... interesting! I suggest that later on (when time is right), you add a minor update (at the end) like "*my script entered our pipeline this afternoon*".  
  > **username_4**: @username_5 I said probably, not guarantee, could be next week or later also ;)  
  > **username_5**: Better late then never, n'est-çe pas?  
  > **username_0**: I get `unexpected EOF while looking for matching '` on the line with `awk -v REGION="$REGION" -v DRUN="$DRUN" '` ?  
  > **username_4**: @username_0 On which distribution ? I assume the problem comes from which shell is effectively called by `/bin/sh`. Replacing carriage returns by `;` in the awk script should fix, removing a part of readability  
  > **username_4**: @username_0 and just noticed I forgot a pair of {} for the commands within the `if` while copy/pasting  
  > **username_0**: I'm running bash 3.2.57(1)-release - not sure which carriage returns should be changed, could you provide an edit and/or another snippet with the change?  
  > **username_4**: @username_0 Edited with a stripped version, without the comments in the awk script and as one liner  
  > **username_0**: Perfect, thanks for editing! Works exactly as intended.  
  > **username_9**: I needed a list of snapshot that was easy to check, and potentially remove some entries from, before actually deleting the stuff, as I had some manually created snapshots that I wanted to keep, even though no AMI referenced them. So I used you code as a base for a new scripts for supporting this: https://gist.github.com/Kreinoee/8d80ff8710f983cfc096be3afa641216  
  
  ---
  
  ### Answer by username_2 on 2017-09-11. Score: 5
  
  I used the following script on GitHub by Rodrigue Koffi (bonclay7) and it works pretty good.
  
  <https://github.com/bonclay7/aws-amicleaner>
  
  Command:
  
  ```
  amicleaner --check-orphans
  
  ```
  
  From the documentation [blog post](http://techblog.d2-si.eu/2017/06/15/cleaning-your-amazon-machine-images.html) it does some more things:
  
  > It actually does a bit more than that, at of today it allows:
  >
  > * Removing a list of images and associated snapshots
  > * Mapping AMIs:
  >   + Using names
  >   + Using tags
  > * Filtering AMIs:
  >   + used by running instances
  >   + from autoscaling groups (launch configurations) with a desired capacity set to 0
  >   + from launch configurations detached from autoscaling groups
  > * Specifying how many AMIs you want to keep
  > * Cleaning orphan snapshots
  > * A bit of reporting
  
  
  ---
  
  ### Answer by username_3 on 2017-03-22. Score: 3
  
  Here is one script which can help you find orphaned snapshots
  
  ```
  comm -23 <(echo $(ec2-describe-snapshots --region eu-west-1 | grep SNAPSHOT | awk '{print $2}' | sort | uniq) | tr ' ' '\n') <(echo $(ec2-describe-images --region eu-west-1 | grep BLOCKDEVICEMAPPING | awk '{print $3}' | sort | uniq) | tr ' ' '\n') | tr '\n' ' '
  
  ```
  
  (from [here](http://www.robertsindall.co.uk/blog/how-to-clean-up-amazon-ebs-volumes-and-snapshots/))
  
  Also you can check this article from [serverfault](https://serverfault.com/questions/611831/find-all-snapshots-created-by-ami-where-ami-is-deleted)
  
  P.S. Of course you can change the region to reflect your
  
  P.P.S. Here is updated code:
  
  ```
   comm -23 \
  <(echo $(aws ec2 describe-snapshots --region eu-west-1 |awk '/SNAPSHOT/ {print $2}' | sort -u) | tr ' ' '\n') \
  <(echo $(aws ec2 describe-images --region eu-west-1 |  awk '/BLOCKDEVICEMAPPING/ {print $3}' | sort -u) | tr ' ' '\n') | tr '\n' ' '
  
  ```
  
  The sample exaplanations what the code do is:
  
  ```
  echo $(aws ec2 describe-snapshots --region eu-west-1 | awk '/SNAPSHOT/ {print $2}' | sort -u) | tr ' ' '\n')
  
  ```
  
  send to STDOUT the list of snapshots. this construction:
  
  ```
  <(...)
  
  ```
  
  create virtual temporary filehandler to make `comm` command read from two "files" and compare them
  
  > **Comments:**
  > **username_0**: Did you test it? I found the same article but can't get it to work. If you can, user error on my end, but I fear it may be outdated based on the age of the article.  
  > **username_3**: @username_0, can check it tomorrow  
  > **username_4**: Command see have changed, use aws ec2 describe/delete  
  > **username_3**: @username_4, thank you. Let me confirm it tomorrow and will edit my answer :)  
  > **username_4**: I did found the same source, but chaining hero awk sort and uniq makes my shell coder side sad, I'll post my version tomorrow :)  
  > **username_5**: I don't understand the magic in the included script. Can you think of a way to extend your answer a bit to add some explanation about it?  
  > **username_3**: @username_5, give me time till tomorrow, will simplify and explain the script :)  
  > **username_5**: Fine for me, just wanted to provide you some (constructive) feedback to let you know that what probably looks like regular English to an expert (like you), looks pretty much like Chinese to me, ok? PS: and it doesn't sound Flemish either ... Drop me an extra comment if you want to notify me after you're done (if you want my updated feedback then).  
  > **username_3**: @username_5, now you can check updated answer :)  
  > **username_5**: Looks like quite some progress. But IMO te PPS is confusing as related to what was in front of it already in the prior version. Why not just integrate it all without such PPS? Also, there are some typos and punctuation issues (like 'commend'?) that you may want to address, no?  
  
  ---
  
  ### Answer by username_6 on 2017-03-23. Score: 2
  
  [Here](https://gist.github.com/daniilyar/45d3fc1867bf435d8c21e9e4864ff472) is a GitHub Gist code snippet of exactly what you are asking for by Daniil Yaroslavtsev.
  
  It uses the list of all images and their snapshots and compares the IDs to list of all snapshot IDs. Whatever remains are the orphaned ones. The code works in the same principle as the answer above, but is better formatted and slightly more readable.
  
  The code takes advantage of the JMESPath with
  `--query Snapshots[*].SnapshotId` option (you can also use jp command line utility for that, if its already in your distribution. The formats the output as text with `--output text`. Here is a [link](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-snapshots.html) to API reference and few examples. It is slightly more elegant than a long chain of grep/awk/sort/uniq/tr pipes.
  
  **Warning by username_7**: Don't mistake with 'jq' utility which uses different query language to parse json documents.
  
  > **Comments:**
  > **username_7**: Just FYI, the jq command line utility is *not* the same JSON query language as what the "aws" command uses. The "aws" command uses JMESPath.  
  > **username_6**: Thank you for pointing that out. I've learned something new today.  
  
  ---
  
  ### Answer by username_8 on 2019-06-30. Score: 0
  
  I've written [snapshots.py](https://gist.github.com/Eyjafjallajokull/4e917414cfb191391f9e51f6a8c3e46a) script which iterates over all snapshots (in defined list of regions) and generates `report.csv`. This file contains information about instance, AMI and volume referenced by all snapshots.
  
  There is also command to interactively remove dangling snapshots.
  
  
  ---
  
  