Skip to content

Instantly share code, notes, and snippets.

@alphapapa
Last active June 21, 2021 16:03
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save alphapapa/3cba3ff196147ad42bac to your computer and use it in GitHub Desktop.
Save alphapapa/3cba3ff196147ad42bac to your computer and use it in GitHub Desktop.
Mangle man pages to show just the parts you need (suitable for aliasing to "man")
#!/bin/bash
less_command='| less $less_no_init -aiF -Ps"Manual page\: $man_page (?ltline %lt?L/%L.:byte %bB?s/%s..? (END):?pB %pB\%..)"'
# Get section
if [[ $1 =~ [0-9]+ ]]
then
section=$1
shift
fi
# Find the longest set of args that gets a man page
man_page=("$@")
while ! command man -w $(echo "${man_page[@]}" | tr " " "-") &>/dev/null
do
patterns+=( ${man_page[-1]} )
unset man_page[-1]
done
# For some reason, using an array substitution in the prompt string in
# less_command isn't working, so work around that by turning it into a
# plain string
man_page="${man_page[@]}"
# Build grep command
if [[ ${patterns[@]} ]]
then
grep_command="| grep -i -C4 --color=always -- ${patterns[@]}"
fi
command="command man $section $man_page $grep_command"
# Check screen and output sizes
tty_lines=$(tput lines)
output_lines=$(eval "$command" | wc -l)
# If output < screen size, use less with -X
[[ $output_lines -lt $tty_lines ]] && less_no_init="-X"
# Display the page
eval "$command $less_command"
#!/bin/bash
# Get section
if [[ $1 =~ [0-9]+ ]]
then
section=$1
shift
fi
# Find the longest set of args that gets a man page
args=("$@")
while ! command man -w $(echo "${args[@]}" | tr " " "-") &>/dev/null
do
patterns+=( ${args[-1]} )
unset args[-1]
done
# Build grep command
if [[ ${patterns[@]} ]]
then
grepCommand="| grep -i -C4 --color=always -- ${patterns[@]} | less -RFX"
else
grepCommand=" | less -RFX"
fi
# Do it
eval "command man $section ${args[@]} $grepCommand"
@alphapapa
Copy link
Author

You can run this script as a replacement for man. For example:

$ mangle find
FIND(1)                                                                                                    General Commands Manual                                                                                                    FIND(1)

NAME
       find - search for files in a directory hierarchy

SYNOPSIS
       find [-H] [-L] [-P] [-D debugopts] [-Olevel] [path...] [expression]

DESCRIPTION
       This  manual  page  documents...

Or:

$ mangle find -mtime
       -d     A synonym for -depth, for compatibility with FreeBSD, NetBSD, MacOS X and OpenBSD.

       -daystart
              Measure times (for -amin, -atime, -cmin, -ctime, -mmin, and -mtime) from the beginning of today rather than from 24 hours ago.  This option only affects tests which appear later on the command line.

       -depth Process each directory's contents before the directory itself.  The -delete action also implies -depth.

--
       -mmin n
              File's data was last modified n minutes ago.

       -mtime n
              File's data was last modified n*24 hours ago.  See the comments for -atime to understand how rounding affects the interpretation of file modification times.

       -name pattern
--

It also handles multi-part man page names, e.g.:

$ mangle git checkout -b
SYNOPSIS
       git checkout [-q] [-f] [-m] [<branch>]
       git checkout [-q] [-f] [-m] --detach [<branch>]
       git checkout [-q] [-f] [-m] [--detach] <commit>
       git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
       git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
       git checkout [-p|--patch] [<tree-ish>] [--] [<paths>...]
--
           committed to the <branch>.

           If <branch> is not found but there does exist a tracking branch in exactly one remote (call it <remote>) with a matching name, treat as equivalent to

               $ git checkout -b <branch> --track <remote>/<branch>
...

@derimagia
Copy link

Awesome! Great work - I modified this to fix some of the issues with it:

https://gist.github.com/derimagia/e57ae185b043f162180b

  • Made it work with bash that doesn't support negative indexes
  • By default uses the MANPAGER argument
  • if it can't find something it won't go in a loop forever
  • Fixed search when you type multiple words (mangle git basic concepts)
  • (For my own personal use at least) Changed search to be case-sensitive since "-F" is different than "-f" when searching man

@alphapapa
Copy link
Author

That's great, thanks for sharing that!

Made it work with bash that doesn't support negative indexes

Ah, I see that those were added in Bash 4.3. I guess I never had occasion to use them before, haha.

By default uses the MANPAGER argument

Good idea!

if it can't find something it won't go in a loop forever

This one puzzles me: I can't seem to cause this. Could this be because of different Bash versions? I'm using Bash 4.3.11.

Fixed search when you type multiple words (mangle git basic concepts)

Nice! I guess I had never actually done that before. I think I'll try using egrep with multiple patterns here too.

There is one little feature I have working in my copy but haven't uploaded: when the matches fit in the current terminal, it causes less to exit immediately and leave the output on the screen. If it doesn't fit on the screen, it runs less normally and resets the screen on exit. I figured that not everyone would want that, but I find it pretty handy. What do you think?

@derimagia
Copy link

You should throw this in a proper repo so people can contribute back, I can see it being useful to others. I would have liked to pull request that stuff in.

For background I use the default bash in mac - but only because I never use it, I use ZSH as my primary shell. (I probably should update bash though...)

Default Bash:
❯ bash --version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15) Copyright (C) 2007 Free Software Foundation, Inc.

In terms of the infinite loop, I like you're right, I think I was only getting that when I was debugging the bash negative index issue. It seems that once $args[@] get down to nothing, it'll just return the command "man -w" which should succeed and get you out of the loop.

In terms of the feature, I just found out about a neat less argument "less -X" that pretty much does that. It's actually my default MANPAGER - it essentially makes it so it doesn't clear/reset the screen when you man. (Try mangle less -X ;))

@alphapapa
Copy link
Author

@derimagia

You should throw this in a proper repo so people can contribute back, I can see it being useful to others. I would have liked to pull request that stuff in.

I think I will do that, thanks.

Wow, that Bash version is old! :)

In terms of the feature, I just found out about a neat less argument "less -X" that pretty much does that. It's actually my default MANPAGER - it essentially makes it so it doesn't clear/reset the screen when you man. (Try mangle less -X ;))

Yep, that's what I was referring to. I made it so mangle only does that if the output fits on the screen, otherwise it uses a normal pager that resets the terminal. I just posted the version that does that, it's up at the top above the previous version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment