#!/usr/bin/env bash # lesscomplete, a helper script for the _less completion script # synced with lesspipe 2.12 # Author: Wolfgang Friebel (wp.friebel AT gmail.com) #( [[ -n 1 && -n 2 ]] ) > /dev/null 2>&1 || exec zsh -y --ksh-arrays -- "$0" ${1+"$@"} has_cmd () { command -v "$1" > /dev/null } fileext () { fn=${1##*/} case "$fn" in .*.*) extension=${fn##*.};; .*) extension=;; *.*) extension=${fn##*.};; esac echo "$extension" } filetype () { # do not depend on the file extension, if possible fname="$1" if [[ "$1" == - || -z $1 ]]; then declare t t=$(nexttmp) head -c 1000000 > "$t" 2>/dev/null [[ -z $fileext ]] && fname="$t" || fname="$fileext" set "$t" "$2" fi fext=$(fileext "$fname") ### get file type from mime type declare ft ft=$(file -L -s -b --mime "$1" 2> /dev/null) [[ $ft == *=* ]] && fchar="${ft##*=}" || fchar=utf-8 fcat="${ft%/*}" ft="${ft#*/}"; ft="${ft%;*}"; ft="${ft#x-script.}"; ft="${ft#x-}" ftype="${ft#vnd\.}" ### get file type from 'file' command for an unspecific result if [[ "$fcat" == application && "$ftype" == octet-stream || "$fcat" == text && $ftype == plain ]]; then ft=$(file -L -s -b "$1" 2> /dev/null) if [[ $ft == data ]]; then case "$fext" in br|bro|tbr) ftype=brotli ;; lz4|lt4|tz4|tlz4) ftype=lz4 ;; esac fi fi echo "$ftype:$fchar:$fcat" } nexttmp () { declare new="$tmpdir/lesspipe.$RANDOM.${ft%%:*}" echo "$new" } istemp () { prog="$1" shift if [[ "$1" == - ]]; then shift t=$(nexttmp) cat > "$t" $prog "$t" "$@" else $prog "$@" fi } show () { file1="${1%%"$sep"*}" rest1="${1#"$file1"}" while [[ "$rest1" == "$sep$sep"* ]]; do if [[ "$rest1" == "$sep$sep" ]]; then break else rest1="${rest1#"$sep$sep"}" file1="${rest1%%"$sep"*}" rest1="${rest1#"$file1"}" file1="${1%"$rest1"}" fi done if [[ ! -e "$file1" && "$file1" != '-' ]]; then exit 1 fi rest11="${rest1#"$sep"}" file2="${rest11%%"$sep"*}" rest2="${rest11#"$file2"}" while [[ "$rest2" == "$sep$sep"* ]]; do if [[ "$rest2" == "$sep$sep" ]]; then break else rest2="${rest2#"$sep$sep"}" file2="${rest2%%"$sep"*}" rest2="${rest2#"$file2"}" file2="${rest11%"$rest2"}" fi done rest2="${rest11#"$file2"}" rest11="$rest1" if [[ "${cmd[*]}" == "" ]]; then ft=$(filetype "$file1") get_unpack_cmd "$ft" "$file1" "$rest1" if [[ "$cmd" != "" && -z $colorizer ]]; then show "-$rest1" else # if nothing to convert, exit without a command isfinal "$ft" "$file1" "$rest11" fi elif [[ "$c1" == "" ]]; then c1=("${cmd[@]}") ft=$("${c1[@]}" | filetype -) || exit 1 get_unpack_cmd "$ft" "$file1" "$rest1" if [[ "$cmd" != "" && -z $colorizer ]]; then show "-$rest1" else "${c1[@]}" | isfinal "$ft" - "$rest11" fi elif [[ "$c2" == "" ]]; then c2=("${cmd[@]}") ft=$("${c1[@]}" | "${c2[@]}" | filetype -) || exit 1 get_unpack_cmd "$ft" "$file1" "$rest1" if [[ "$cmd" != "" && -z $colorizer ]]; then show "-$rest1" else "${c1[@]}" | "${c2[@]}" | isfinal "$ft" - "$rest11" fi elif [[ "$c3" == "" ]]; then c3=("${cmd[@]}") ft=$("${c1[@]}" | "${c2[@]}" | "${c3[@]}" | filetype -) || exit 1 get_unpack_cmd "$ft" "$file1" "$rest1" if [[ "$cmd" != "" && -z $colorizer ]]; then show "-$rest1" else "${c1[@]}" | "${c2[@]}" | "${c3[@]}" | isfinal "$ft" - "$rest11" fi elif [[ "$c4" == "" ]]; then c4=("${cmd[@]}") ft=$("${c1[@]}" | "${c2[@]}" | "${c3[@]}" | "${c4[@]}" | filetype -) || exit 1 get_unpack_cmd "$ft" "$file1" "$rest1" if [[ "$cmd" != "" && -z $colorizer ]]; then show "-$rest1" else "${c1[@]}" | "${c2[@]}" | "${c3[@]}" | "${c4[@]}" | isfinal "$ft" - "$rest11" fi elif [[ "$c5" == "" ]]; then c5=("${cmd[@]}") ft=$("${c1[@]}" | "${c2[@]}" | "${c3[@]}" | "${c4[@]}" | "${c5[@]}" | filetype -) || exit 1 get_unpack_cmd "$ft" "$file1" "$rest1" if [[ "$cmd" != "" && -z $colorizer ]]; then echo "$0: Too many levels of encapsulation" else "${c1[@]}" | "${c2[@]}" | "${c3[@]}" | "${c4[@]}" | "${c5[@]}" | isfinal "$ft" - "$rest11" fi fi } get_unpack_cmd () { fchar="${1%:*}"; fchar="${fchar#*:}" fcat="${1##*:}" x="${1%%:*}" cmd=() if [[ "$3" == $sep$sep ]]; then return fi declare t # uncompress case $x in gzip|bzip2|lzip|lzma|xz|brotli|compress) # remember name of uncompressed file [[ $2 == - ]] || fileext="$2" fileext=${fileext%%.gz}; fileext=${fileext%%.bz2} [[ $x == compress ]] && x=gzip has_cmd "$x" && cmd=("$x" -cd "$2") && return ;; zstd) has_cmd zstd && cmd=(zstd -cdqM1073741824 "$2") && return ;; lz4) has_cmd lz4 && cmd=(lz4 -cdq "$2") && return ;; esac [[ "$3" == "$sep" ]] && return file2=${3#"$sep"} file2=${file2%%"$sep"*} # remember name of file to extract or file type [[ -n "$file2" ]] && fileext="$file2" # extract from archive rest1="$rest2" rest2= prog= case "$x" in tar) prog=tar has_cmd bsdtar && prog=bsdtar ;; rpm) { has_cmd cpio && has_cmd rpm2cpio; } || { has_cmd bsdtar; } && cmd=(isrpm "$2" "$file2") ;; java-archive|zip) { has_cmd bsdtar && prog=bsdtar; } || { has_cmd unzip && prog=unzip; } ;; debian*-package) { has_cmd ar || has_cmd bsdtar; } && cmd=(isdeb "$2" "$file2") ;; rar) { has_cmd bsdtar && prog=bsdtar; } || { has_cmd unrar && prog=unrar; } || { has_cmd rar && prog=rar; } ;; ms-cab-compressed) { has_cmd bsdtar && prog=bsdtar; } || { has_cmd cabextract && prog=cabextract; } ;; iso9660-image) { has_cmd bsdtar && prog=bsdtar; } || { has_cmd isoinfo && prog=isoinfo; } ;; cpio) { has_cmd cpio && prog=cpio; } || { has_cmd bsdtar && prog=bsdtar; } ;; archive) prog='ar' has_cmd bsdtar && prog=bsdtar esac # 7z formats and fall back to 7z supported formats if [[ -z $prog ]]; then case "$x" in 7z-compressed|lzma|xz|cab|arj|bzip2|cpio|iso) { has_cmd 7zz && prog=7zz; } || { has_cmd 7zr && prog=7zr; } || { has_cmd 7z && prog=7z; } || { has_cmd 7za && prog=7za; } ;; esac fi [[ -n $prog ]] && cmd=(isarchive "$prog" "$2" "$file2") if [[ -n ${cmd[0]} ]]; then [[ -n "$file2" ]] && file2= && return colorizer='cat' fi } isfinal () { if [[ -n $cmd && $colorizer == 'cat' ]]; then "${cmd[@]}" fi } isarchive () { prog=$1 if [[ -n $3 ]]; then case $prog in tar|bsdtar) $prog Oxf "$2" "$3" 2>/dev/null;; rar|unrar) istemp "$prog p -inul" "$2" "$3" ;; ar) istemp "ar p" "$2" "$3" ;; unzip) istemp "unzip -avp" "$2" "$3" ;; cabextract) istemp cabextract2 "$2" "$3" ;; isoinfo) istemp "isoinfo -i" "$2" "-x$3" ;; cpio) if [[ "$2" == - ]]; then cpio -i --quiet --to-stdout "$3" else cpio -i --quiet --to-stdout --file "$2" "$3" fi ;; 7zz|7za|7zr) istemp "$prog e -so" "$2" "$3" esac else case $prog in tar|bsdtar) $prog tf "$2" ;; rar|unrar) istemp "$prog v" "$2"|grep -E ':[0-9][0-9] '|cut -c 67- ;; ar) istemp "ar t" "$2" ;; unzip) istemp "unzip -Z -1" "$2" ;; cabextract) istemp "cabextract -l" "$2" |grep -E '[0-9] \|'|sed 's/.*| //' ;; isoinfo) t="$2" istemp "isoinfo -d -i" "$2" >/dev/null istemp "isoinfo -d -i" "$t"| grep -E '^Joliet' && joliet=J isoinfo -fR"$joliet" -i "$t" ;; cpio) if [[ "$2" == - ]]; then cpio -t --quiet else cpio -t --quiet --file "$2" fi ;; 7zz|7za|7zr) istemp "$prog l" "$2"|grep -E '^[0-9][0-9][0-9[0-9]'|cut -c 54-|grep -Ev ' files$' esac fi } cabextract2 () { cabextract -pF "$2" "$1" } isrpm () { if [[ -z "$2" ]]; then if has_cmd bsdtar; then bsdtar tf "$1" else rpm2cpio "$1" 2>/dev/null|cpio -i -t 2>/dev/null fi elif has_cmd bsdtar; then bsdtar xOf "$1" "$2" else rpm2cpio "$1" 2>/dev/null|cpio -i --quiet --to-stdout "$2" fi } isdeb () { if [[ "$1" = - ]]; then t=$(nexttmp) cat > "$t" set "$t" "$2" fi if has_cmd bsdtar; then data=$(bsdtar tf "$1" "data*") if [[ -z "$2" ]]; then bsdtar xOf "$1" "$data" | bsdtar tf - else bsdtar xOf "$1" "$data" | bsdtar xOf - "$2" fi else data=$(ar t "$1"|grep data) ft=$(ar p "$1" "$data" | filetype -) get_unpack_cmd "$ft" - if [[ -z "$2" ]]; then ar p "$1" "$data" | "${cmd[@]}" | tar tf - else ar p "$1" "$data" | "${cmd[@]}" | tar xOf - "$2" fi fi } # the main program set +o noclobber setopt sh_word_split 2>/dev/null a="${1/#\~/$HOME}" a="${a//\\}" sep=: # file name separator altsep='=' # alternate separator character if [[ -e "$a" && "$a" == *"$sep"* ]]; then sep=$altsep elif [[ "$a" == *"$altsep"* ]]; then [[ -e "${a%%"$altsep"*}" ]] && sep=$altsep fi tmpdir=${TMPDIR:-/tmp}/lesspipe."$RANDOM" [[ -d "$tmpdir" ]] || mkdir "$tmpdir" [[ -d "$tmpdir" ]] || exit 1 trap 'rm -rf "$tmpdir";exit 1' INT trap 'rm -rf "$tmpdir"' EXIT trap - PIPE t=$(nexttmp) # make LESSOPEN="|- ... " work if [[ $LESSOPEN == *\|-* && $1 == - ]]; then cat > "$t" [[ -n "$fext" ]] && t="$t$sep$fext" a="$t" nexttmp >/dev/null fi show "$a"