Share your file-opener script - seninha - 30-05-2020
Most of us have an handy script for opening files and/or links given as arguments. This is, sometimes, one of our most used scripts. Use this thread to share your file-opener or link-opener scripts and steal ideas from others.
Here is mine, I call it xopen.
Code: #!/bin/sh
# xopen: open file with proper command; use file in $MIMEFILE as rules file
# this file in public domain
usage() {
echo "usage: xopen [-c mimefile] filename" >&2
exit 1
}
# get mimetype of a file using the file(1) utility
getfilemime() {
file -ib "$@" | cut -d';' -f1
}
# get lowercase extension of a file
getextension() {
echo "${1##*.}" | tr '[:upper:]' '[:lower:]'
}
# get mimetype of a url
geturlmime() {
protocol=$(printf "%s" "$@" | sed 's/^\([a-zA-Z]\+\):.*/\1/')
case "$protocol" in
http|https)
echo text/html
;;
magnet)
echo application/x-bittorrent
;;
irc)
echo x-scheme-handler/irc
;;
esac
unset protocol
}
# get command to open file or url
getcmd() {
while read -r line
do
line=${line%%#*} # remove comments
[ -z "$line" ] && continue # ignore blank lines
pattern="$(echo $line | cut -s -d: -f1 | sed -E 's/[ ]*$//; s/\|/ /g')"
cmd="$(echo $line | cut -s -d: -f2 | sed -E 's/^[ ]*//')"
cmd="$(eval echo $cmd)"
# using case for matching patterns to avoid forking
for i in $pattern
do
case $1 in
$i) echo "$cmd" && return ;;
esac
done
done < "$MIMEFILE"
}
# execute command $1 to open file or url $2
xopen() {
trap "" 1 15
echo xopen: opening $search with $1 >&2
exec $1 "${2}" &
}
while getopts 'c:' c
do
case "$c" in
c)
MIMEFILE="$OPTARG"
;;
*)
usage
;;
esac
done
shift $((OPTIND -1))
[ "$#" -ne 1 ] && usage
# test whether MIMEFILE is not set
[ -z "$MIMEFILE" ] && echo 'xopen: $MIMEFILE is not set' >&2 && exit 1
# get mimetype and file extension
if [ -e "$@" ];
then # it's a file
mime=$(getfilemime "$@")
extension=$(getextension "$@")
else # it's a url
mime=$(geturlmime "$@")
fi
[ -z "$extension$mime" ] && echo "xopen: unknown file or url type" >&2 && exit 1
# get command to open file or url
cmd=$(getcmd "$extension") # try first to open by file extension
[ -z "$cmd" ] && cmd=$(getcmd "$mime") # then try to open by mimetype
[ -z "$cmd" ] && echo "xopen: cannot find an command to open $@ ($mime)" >&2 && exit 1
# open file or url with $cmd
xopen "$cmd" "$@"
It gets its configuration from a file specified in the environment variable $MIMEFILE (or after the -c option). Each line in this file is composed by a mimetype or a file extension followed by a colon, followed by the command that opens a file with that mimetype or extension. Here is my $MIMEFILE:
Code: # web
text/html: palemoon
# text
text/*: $TERMCMD -e $EDITOR
application/x-empty: $TERMCMD -e $EDITOR
application/x-shellscript: $TERMCMD -e $EDITOR
inode/x-empty: $TERMCMD -e $EDITOR
inode/directory: $TERMCMD -e fm
# Docs
application/pdf: zathura
application/postscript: zathura
application/epub*: zathura
image/*djvu: zathura
# media
application/octet-stream: mpv
video/*: mpv
audio/*: mpv
# image
image/*: sxiv
# Man pages
0|1|2|3|4|5|6|7: $TERMCMD -e man
Now share yours!
RE: Share your file/link-opener script - z3bra - 31-05-2020
Mine is self-contained, though I like your way to use the mailcap entry… I'll look this out later.
I cleaned up mine a bit. The cool stuff about it (I think) is that you can pipe data to it and open it. Not only URIs:
Code: curl -s 'https://random.tld/image.png' | plumb -s
This would cache the file locally, and open it with the according mime entry.
Here is the full script:
Code: #!/bin/sh
#
# open things from uri
cachedir=$HOME/.cache/plumber
usage() {
echo "usage: $(basename $0) [-h] [uri]" >&2
}
peekmime() {
curl -sSfL "$1" | cut -b-16 | file -ib - | cut -d\; -f1
}
# return a uri to a local file (download if necessary)
localuri() {
local="$1"
if [ ! -f "$1" ]; then
tmp=$(mktemp)
curl -o $tmp -sSfL "$1"
local=$(cachefile "$tmp" "${mime##*/}")
rm $tmp
fi
printf '%s\n' "$local"
}
# copy file to cache
cachefile() {
mkdir -p $cachedir
hash=$(sha256sum "$1"|cut -d' ' -f1)
cp "$1" $cachedir/${hash}.$2
printf '%s/%s.%s\n' "$cachedir" "$hash" "$2"
}
# prompt for a command to open uri
prompt() {
dmenu_path | dmenu -p "$1" -l 8
}
clip="$(xsel -o 2>/dev/null)"
while getopts "hs" OPT; do
case $OPT in
s) slurp=$(mktemp -p $cachedir) ;;
h) usage; exit 0 ;;
*) usage; exit 1 ;;
esac
done
shift $((OPTIND - 1))
# fallback to clipboard when not uri given
uri="${1:-$clip}"
# special arg "-" read uri(s) from stdin
if [ "$uri" = "-" ]; then
cat | xargs -P$(nproc) -n1 $0
fi
# can read file _content_ from stdin, then process it
if [ -n "$slurp" ]; then
cat > $slurp
uri="$slurp"
fi
[ -z "$uri" ] && exit 1
if [ -f "$uri" ]; then
mime=$(file -ib "$uri" | cut -d\; -f1)
else
proto="${uri%%:*}"
case $proto in
mailto) mime='application/x-mail' ;;
magnet) mime='application/x-bittorrent' ;;
*) mime="$(peekmime $uri)" ;;
esac
fi
if [ -n "$slurp" ]; then
uri="$(cachefile $slurp ${mime##*/})"
rm "$slurp"
fi
case "$mime" in
text/html) exec firefox "$uri" ;;
video/*) exec mplayer -cache 512 "$uri" ;;
image/gif) exec mplayer -loop 0 $(localuri "$uri") ;;
image/*) exec meh $(localuri "$uri") ;;
text/*) exec st -e less $(localuri "$uri") ;;
application/x-mail) exec st -e mutt $uri ;;
application/x-bittorrent) exec st -e rtorrent $uri ;;
*) exec $(prompt) "$uri" ;;
esac
RE: Share your file/link-opener script - venam - 31-05-2020
I rely on the freedesktop utility xdg-open as it already has full integration with mime types and desktop files. I kind of pointed it a bit in this discussion about default programs.
So what I usually do is xdg-open, and if it doesn't call the program I want then I can switch it using mimeopen -a. In the case where my program isn't listed, I create a desktop file in ~/.local/share/applications, then update-desktop-database. Most of the time, this solves my issues, otherwise I can dive into adding my own mimetype in ~/.local/share/mime/application.
RE: Share your file-opener script - jkl - 10-02-2021
Almost on-topic: In a C++ software of mine (which I really should develop further... some day), I wrote a function to open a text file with the default editor. I would guess that, if one removes the VISUAL/EDITOR checks, it fulfills this thread’s needs as well.
Note that sanitizing the filename needs to be done beforehand. Better don’t make this function publicly callable. :)
Code: inline bool openWithEditor(const char* filename) {
// Opens <filename> in your default editor.
#ifdef _WIN32
// Windows version, using the Windows API.
return reinterpret_cast<int>(ShellExecuteA(NULL, "open", filename, NULL, NULL, SW_SHOW)) > 32;
#else
// Other system, other ways...
string editor = "";
if (getenv("VISUAL") != NULL) {
editor = getenv("VISUAL");
}
else if (getenv("EDITOR") != NULL) {
editor = getenv("EDITOR");
}
else {
#ifdef __linux__
editor = "xdg-open";
#else
// No standard editor found. Sorry!
return false;
#endif
}
return system(string(editor + " \"" + filename + "\"").c_str()) == 0;
#endif
}
RE: Share your file-opener script - neeasade - 13-02-2021
Here is my current "go to what I'm looking at" emacs function: https://github.com/neeasade/emacs.d/blob/001b6d956373a436ad5370dd9f71150548324546/lisp/trees/follow.el#L54-L60
The goal is to handle various fallbacks, through org links, files, urls, and code definitions.
RE: Share your file-opener script - venam - 07-03-2022
There's a discussion on lobsters related to this. An interesting custom solution is this one from vermaden.
|