Álvaro Ramírez
SHA-256 hash from URL, the easy way
From time to time, I need to generate a SHA-256 hash from a file hosted on some server. For me, this flow typically goes something along the lines of:
- Copy the file URL from browser.
- Drop to Emacs eshell.
- Change current directory.
- Type "curl -o file"
- Paste the file URL.
- Run curl command.
- Type "shasum -a 256 file".
- Run shasum command.
- Copy the generated hash.
- Maybe delete the downloaded file?
We can maybe shave some steps off by downloading directly from the browser, though that may also bring additional clicks and navigating to a download location.
Amongst the steps, shasum is the star player, and its output can be seen below.
shasum -a 256 path/to/downloaded/file
3da351027e5b1495c7c7fe4abbf8d7ac9625da3604be5a35c9a9cbb92f6f955a path/to/downloaded/file
Not a huge deal. One can copy the hash from the output, but why go through multiple small manual steps when I know I can get Emacs to simplify the lot? I've expedited a similar flow in the past when cloning git repos. Let's simplify again so hashing a hosted file boils down to:
- Copy the file URL from browser.
- Run an Emacs interactive command.
This is where I pull out dwim-shell-command (a little package I wrote) and glue the lot to get an expedited experience.
There isn't much to the function other than glueing a little elisp and a shell script via dwim-shell-command
for some buffer/error handling.
(defun dwim-shell-commands-sha-256-hash-file-at-clipboard-url () "Download file at clipboard URL and generate SHA-256 hash." (interactive) (let ((url (current-kill 0))) (unless (string-match-p "^http[s]?://" url) (user-error "No URL in clipboard")) (dwim-shell-command-on-marked-files "Generate SHA-256 hash from clipboard URL." (format "temp_file=$(mktemp) function cleanup { rm -f $temp_file } trap cleanup EXIT curl --no-progress-meter --location --fail --output $temp_file %s || exit 1 shasum -a 256 $temp_file | awk '{print $1}'" (shell-quote-argument url)) :utils '("curl" "shasum") :on-completion (lambda (buffer process) (if-let ((success (= (process-exit-status process) 0)) (hash (with-current-buffer buffer (string-trim (buffer-string))))) (progn (kill-buffer buffer) (kill-new hash) (message "Copied %s to clipboard" (propertize hash 'face 'font-lock-string-face))) (switch-to-buffer buffer))))))
dwim-shell-commands-sha-256-hash-file-at-clipboard-url
is now in dwim-shell-commands.el, the optional counterpart in dwim-shell-command.
UPDATE
There's better way. Thanks to Philip Kaludercic for suggesting curl -s example.com | sha256sum - | cut -d " " -f1
and Sacha Chua who pinged me about it.
Also note I'm now relying on the <<cb>>
template, since dwim-shell-command replaces it with the clipboard/kill ring.
(defun dwim-shell-commands-sha-256-hash-file-at-clipboard-url () "Download file at clipboard URL and generate SHA-256 hash." (interactive) (unless (string-match-p "^http[s]?://" (current-kill 0)) (user-error "No URL in clipboard")) (dwim-shell-command-on-marked-files "Generate SHA-256 hash from clipboard URL." "curl -s '<<cb>>' | sha256sum - | cut -d ' ' -f1" :utils '("curl" "sha256sum") :on-completion (lambda (buffer process) (if-let ((success (= (process-exit-status process) 0)) (hash (with-current-buffer buffer (string-trim (buffer-string))))) (progn (kill-buffer buffer) (kill-new hash) (message "Copied %s to clipboard" (propertize hash 'face 'font-lock-string-face))) (switch-to-buffer buffer)))))