Coder Social home page Coder Social logo

dylanaraps / pure-bash-bible Goto Github PK

View Code? Open in Web Editor NEW
36.3K 747.0 3.3K 232 KB

πŸ“– A collection of pure bash alternatives to external processes.

License: MIT License

Shell 100.00%
bash shell script guide list bible book reference handbook learning

pure-bash-bible's Introduction

Have taken up farming.

pure-bash-bible's People

Contributors

ahmetb avatar amiryal avatar bennn avatar cooloppo avatar crestwave avatar cristeigabriel avatar cuttlerat avatar d3v1an7 avatar dylanaraps avatar enterdot avatar expectocode avatar melongbob avatar mq1 avatar paxperscientiam avatar rahuldaniel avatar rasa avatar sal666 avatar sumbach avatar tebriel avatar turquoise-hexagon avatar txbm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pure-bash-bible's Issues

add example debug script with trap

debug script with trap

  • Example:
function exit_trap() {
        local lc="$BASH_COMMAND" rc=$?
        echo "Command [$lc] exited with code [$rc]"
}

trap exit_trap err

[Enhancement] Sample of obsolete code

Obsolete code

There are a ton of obsolete code samples in nearly every programming language.

Bash samples

Use $()

There is no main reason. $() is new `` is old.

`` vs $()

# Sample
var=`something` vs var=$()

Header use #!/usr/bin/env

Use always #!/usr/bin/env because #!/usr/bin/env searches the path of bash. Not on all linux permutations the default bash location is /bin/bash so always use that.

#!/usr/bin/env vs #!/bin/bash

#Sample
#!/usr/bin/env

Functions

The function key word is not required any more. Don't use that because it reduced the compatibility of different bash versions.

function do_something () {
}

# vs

do_something () {
}

These are only few examples I have a lot more if you want I could submit a PR.

Regards

Chinese version

hello:
I am an Operations Engineer from China.A few days ago,I saw your open source project in github,pure-bash-bible.
I often write some Linux scripts for working.Thank you for opening up your project.It is very helpful for my work.
But its language is English,So I translated it into Chinese,i think It would be helpful for Chinese engineers, I think I should tell you this to get your support.Thank you for your work again.My repository is https://github.com/A-BenMao/pure-bash-bible-zh_CN

curl/wget (need help)

I'm trying to PR a working curl / wget (using /dev/tcp)

set -ex

function __curl() {
  read proto server path <<<$(echo ${1//// })
  DOC=/${path// //}
  HOST=${server//:*}
  PORT=${server//*:}
  [[ x"${HOST}" == x"${PORT}" ]] && PORT=80

  exec 3<>/dev/tcp/${HOST}/$PORT
  echo -en "GET ${DOC} HTTP/1.0\r\nHost: ${HOST}\r\n\r\n" >&3
  (while read line; do
   [[ "$line" == $'\r' ]] && break
  done && cat) <&3
  exec 3>&-
}

__curl http://www.google.com/favicon.ico > mine.ico
md5sum mine.ico

Yet 'im stuck on the && cat to handle the file body (binary)
I'm sure i can use a new file descriptor && echo , but my bash skill ends here 😞
I can link & use a pure bash [1], yet i'm sure there is something more elegant to do here.

[1] https://unix.stackexchange.com/questions/83926/how-to-download-a-file-using-just-bash-and-nothing-else-no-curl-wget-perl-et

basename is not equivalent to the utility

This shouldn't be as hard as dirname; trailing slashes are the crux in the first counter-examples, then there is lack of support for the second optional argument, which nobody knows about anyway:

~ $ basename_pbb() {
    # Usage: basename "path"
    : "${1%/}"
    printf '%s\n' "${_##*/}"
}
~ $ basename_pbb something//

~ $ basename something//
something
~ $ basename_pbb /

~ $ basename /
/
~ $ basename_pbb dir/something thing
something
~$ basename dir/something thing
some

The POSIX standard helps, https://pubs.opengroup.org/onlinepubs/9699919799/

According to this, some compliant implementation could go like this:

  • If string consists entirely of / characters, the result is a single / character.
  • Otherwise:
    • If there are any trailing / characters in string, they shall be removed.
    • If there are any / characters remaining in string, the prefix of string up to and including the last / character in string shall be removed.
  • If the suffix operand is present, is not identical to the characters remaining in string, and is identical to a suffix of the characters remaining in string, the suffix suffix shall be removed from string. Otherwise, string is not modified by this step. It shall not be considered an error if suffix is not found in string.

Meaning that this implementation is spec-conformant:

basename_pbb() {
    # Usage: basename "path" ["suffix"]
    local tmp
    if [[ $1 =~ ^/+$ ]]; then
        tmp=/
    else
        tmp=${1%"${1##*[!/]}"} # $1 without trailing slashes
        tmp=${tmp##*/} # $tmp without its longest prefix ending in a slash
    fi
    [[ $tmp != "$2" ]] && tmp=${tmp%"$2"}
    printf '%s\n' "$tmp"
}

If you want to have fun codegolfing it, be my guest! But don't remove the quotes around $2, because the asterisk and question mark characters are legal in filenames.

lines()

lines() {
    # Usage: lines "file"
    mapfile -tn 0 lines <<<"$1"
   # instead of < "$1"
    printf '%s\n' "${#lines[@]}"
}

Thank you

Hey,
I just want to spread love and say thank you for this awesome tutorial. Keep it up and hope you will continue this project.

Regards,

deltax

`.bashrc`-like file

Would be neat to have a file that could be included from a .bashrc (e.g. source ~/.bashrc-bash-bible). This could also be useful to reproducibility with test.sh

Bash 5.0 breaks reverse_array in scripts

In Bash 5.0 scripts, BASH_ARGV also gets the current function's arguments when extdebug is enabled for the first time, so reverse_array's results are printed twice. Relevant section of the changelog:

The shell doesn't automatically set BASH_ARGC and BASH_ARGV at startup unless it's in debugging mode, as the documentation has always said, but will dynamically create them if a script references them at the top level without having enabled debugging mode.

Compatibility with the old version is available with the compat44 shell option.

Improved lines function

lines function could be easily changed to read from variable, file ( as it does ) and a pipe output. Here is the code that works for me:

Usage: lines < "file" or lines <<< "$variable" or echo something | lines

lines() {
    mapfile -tn 0 lines
    printf '%s\n' "${#lines[@]}"
}

Similar issue that was closed: #85

Caveat for 'split a string on a delimiter'

https://github.com/dylanaraps/pure-bash-bible#split-a-string-on-a-delimiter

The -a option for read isn't available in every version of bash. At a minimum, it doesn't work on macOS's built-in bash (on macOS High Sierra, I'm running bash 3.2.57).

This does work if I upgrade to bash 4+.

For what it's worth, I suspect there may be an alternative pure bash method to split a string into an array, but I haven't been able to come up with a perfectly generic function yet. Related: this is a fun read

add chr() and ord()

ord is usually handled by the external "od" command.

chr() {
  [ "$1" -lt 256 ] || return 1
  printf "\\$(printf '%03o' "$1")"
}

ord() {
  LC_CTYPE=C printf '%d' "'$1"
}

Source

What's the purpose of these instructions?

What's the purpose of these instructions : "${chapter[$i]/$'\n'*}"; : "${_/\# }"; : "${_,,}"in build.sh? I run bash build.sh without them in ubuntu18.04.2 TLS x86_64, it get the same result.

#!/usr/bin/env bash
#
# Turn the single document bible into a book separated by chapters.

main() {
    rm -rf manuscript
    mkdir -p manuscript

    # Split the README.md into chapters based on markers.
    while IFS=$'\n' read -r line; do
        [[ "$chap" ]] && chapter[$i]+="$line"$'\n'
        [[ "$line" == "<!-- CHAPTER START -->" ]] && chap=1
        [[ "$line" == "<!-- CHAPTER END -->" ]]   && { chap=; ((i++)); }
    done < README.md

    # Write the chapters to separate files.
    for i in "${!chapter[@]}"; do
        : "${chapter[$i]/$'\n'*}"; : "${_/\# }"; : "${_,,}"
        printf '%s\n' "${chapter[$i]}" > "manuscript/chapter${i}.txt"
        printf '%s\n' "chapter${i}.txt" >> "manuscript/Book.txt"
    done
}

main

remove_array_dups sorts the array's order

I'm not sure if this was added later as the second example isn't sorted, but on my bash 4.4 and 5.0, associative arrays sort in lexicographical and reverse lexicographical order respectively. Strangely, I don't see the change in the 5.0 changelog, though.

Bypass functions trick does not work

In the "Bypass shell aliases and functions", the trick of using a backslash does not work for functions \ (though it does work for aliases).

This is on my Mac running

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

e.g.

$ logname
sal
$ function logname() { echo 'There is no logname, only Zuul.'; }
$ logname
There is no logname, only Zuul.
$ \logname
There is no logname, only Zuul.

Instead, you can use

$ $(which logname)
sal

or possibly with -f added

see https://salferrarello.com/command-line-which-wrong-result/#skipping-aliases-and-functions for more information.

Misleading use of shebang

Just a bit of forewarning with regard to the "recommended" use of shebangs.

# Right:

    #!/usr/bin/env bash

# Less right:

   #!/bin/bash

Using env by default is not a good habit because as you state above:

The former searches the user's PATH to find the bash binary.

You do not WANT bash looking at a users local path for say, system scripts, things meant to be run by root or any other user. To say the latter is bad, is.. well, bad itself.

PATH can be manipulated, a script can be set readonly.

Took an inordinate amount of time to explain this to a junior sysadmin who was adamant every script on a production host should be changed "because".

Too Long README & Wiki Request

Wiki pages can be created by separating the important parts instead of the too long readme file. I think that's absolutely necessary for better understanding and life-saving. :)

Thanks!

Contribution

First of all thanks for this amazing repository, it's hard to come by a lot of useful tips like this.

I would like to contribute with some of my own personal code, if it's something that interests you.

A redis bash "client library" using only bash internals.

Which BTW I'm sure I can incorporate some improvements from your document.

Another is some random functions from this repository:

Most of the functions on this file only use bash internals, and they are used to manipulate ip addresses, like for example to determine if an IP address belongs to a CIDR block.

If you're interested please let me know if you would like me to do a PR or if you prefer to do it yourself.

Also, these 2 repositories are examples of /dev/tcp usage and bitwise manipulation using bash

Thanks in advance.

Add get first/latest file in a directory

Hi,
first big thanks for the "bible".

I think it might helpful to add more file handling tips like "get filepath from first file in a directory" or "get the filepath for the last modified file in a directory".

Would someone mind to add good solutions to these?

Best regards

uuid alternative

Hi, I don't have time to do a fork and make a pull request, but here is code which might interest you, it provide an alternative to uuid -v4 (or to /proc/sys/kernel/random/uuid )

# generate an uuid -v4 using pure bash
function uuidBash ()
{
    local N B C='89ab'

    for (( N=0; N < 16; ++N ))
    do
        B=$(( $RANDOM%256 ))

        case $N in
            6)
                printf '4%x' $(( B%16 ))
                ;;
            8)
                printf '%c%x' ${C:$RANDOM%${#C}:1} $(( B%16 ))
                ;;
            3 | 5 | 7 | 9)
                printf '%02x-' $B
                ;;
            *)
                printf '%02x' $B
                ;;
        esac
    done
}

Reverse an array example improvement

Two small issues on this example:

  • By using arrray[@] instead of array[*] printf receives multiple arguments, that means that when trying to add another argument to the printf this can get quite confusing, for instance when adding the number of args:
shopt -s extdebug

reverse_array() {
  printf 'Reversed args: %s\nNumber of args: %s\n' "${BASH_ARGV[@]}" "$#"
}

reverse_array 1 2 3

Will output the following:

Reversed args: 3
Number of args: 2
Reversed args: 1
Number of args: 3
  • BASH_ARGV also contains the script arguments (and other potential caller arguments), that means that this example only works in a specific case, for instance if the function call reverse array 1 2 3 is inside the script foo, calling foo a b c from a shell:

Will output:

3
2
1
c
b
a

So if that sounds good I would go with the following:

reverse_array() {
  shopt -s extdebug
  f() { printf '%s\n' "${BASH_ARGV[*]:0:$#}"; }; f "$@"
  shopt -u extdebug
}

reverse_array 1 2 3

With the following output:

3 2 1

rgb2hsl - Something fun I wrote today

This is very likely not perfect but it seems to pass any RGB color I throw at it.

# rgb2hsl - usage: rgb2hsl r g b

rgb_to_hsl() {
    local r g b
    local h s l
    local min max

    # Ensure input is greater than 0.
    ((r=r < 0 ? 0 : ${1:-0}))
    ((g=g < 0 ? 0 : ${2:-0}))
    ((b=b < 0 ? 0 : ${3:-0}))

    # Ensure input is lesser than 255.
    ((r=r > 255 ? 255 : r))
    ((g=g > 255 ? 255 : g))
    ((b=b > 255 ? 255 : b))

    # Convert RGB value to a 0-100 range.
    #
    # This is usually a 0-1 range but we
    # multiply by 100 to "fake" floating
    # point.
    ((r=r * 100 / 255))
    ((g=g * 100 / 255))
    ((b=b * 100 / 255))

    # Give the min variable the maximum
    # possible value. We must set it to
    # something.
    ((min=255))

    # Find the minimum and maximum RGB
    # values for use below.
    ((min=r < min ? r : min))
    ((max=r > max ? r : max))
    ((min=g < min ? g : min))
    ((max=g > max ? g : max))
    ((min=b < min ? b : min))
    ((max=b > max ? b : max))

    # Calculate the luminace using the
    # above values.
    ((l=(min + max) / 2))

    # Calculate the saturation using a
    # different formula based on its
    # value.
    #
    # Again, we multiply the values by
    # 100 to "fake" floating points.
    ((s=min == max
        ? 0
        : l < 50
            ? (max - min) * 100 / (max + min)
            : (max - min) * 100 / (200 - max - min)
    ))

    # Calculate the hue based on which
    # RGB value is the maximum.
    ((h=s == 0 ? 0
        : r == max
            ? (g - b) * 100 / (max - min)
        : g == max
            ? 200 + (b - r) * 100 / (max - min)
        : b == max
            ? 400 + (r - g) * 100 / (max - min)
        : 0
    ))

    # Convert the calculation result into
    # degrees. Divide by 100 to reverse the
    # floating point hacks.
    ((h=h * 60 / 100))

    printf '%s\n' "$h $s $l"
}

rgb_to_hsl 18 233 45

Multidimensional associative arrays

With bash version 4+ and associative arrays, it's possible to create multidimensional arrays. Here an example:

#written on phone and untested, apologies for mistakes!
declare -A animals
animalNames=()
addAnimal() {
    animalNames+=("$1")
    animals["$1_species"]="$2"
    animals["$1_age"]="$3"
    animals["$1_sound]="$4"
}
addAnimal Milo cat 8 meow
addAnimal Rex dog 2 woof

for animal in $animalNames; do
  echo "$animal is a ${animals[$animal_species]}, it's ${animals[$animal_age]} years old and makes ${animals[$animal_sound]}!"
done

Would you be interested in adding this (and optionally some more helperfunctions) to the bible? I could create a PR in the next few weeks ☺️

dirname is not equivalent to the utility

Here are a few counter-examples:

~ $ dirname_pbb() {
    # Usage: dirname "path"
    printf '%s\n' "${1%/*}/"
}

~ $ dirname dir1/dir2/
dir1
~ $ dirname_pbb dir1/dir2/
dir1/dir2

~ $ dirname dir1/dir2
dir1
~ $ dirname_pbb dir1/dir2
dir1/

~ $ dirname dir1
.
~ $ dirname_pbb dir1
dir1/

In fact I already tried to reimplement that one with variable substitution and found a few corner cases like this, making me unsure I was up to the task without a serious read of… the POSIX spec, I suppose.

TODO

  • Dynamic variable naming.
  • Internal variables.
  • Turn the non-functions into functions.
    • This is so tests can be written.
    • It also shows a working use case for the task.
  • Add a CONTRIBUTING.md.
  • Look into side effects of using shopt and set.
  • /dev/tcp
  • Convert to pdf
    • Add a cover.
    • Add references.
  • Write some in-depth descriptions for all of the functions.
    • How they work.
    • What tools they replace.
    • Caveats
    • ???
  • Add argument parsing.

Random array element function

Hi,

Just noticed this repo and thought I would share this function that I came up with a few days ago:

function random_array_element {
    declare -n array="$1"  # namerefs are cool!  And it even works with the array being a local variable in another function!

    local length=${#array[@]}
    local index=$(( RANDOM % length))
    local choice=${array[$index]}

    echo "$choice"
}

Used like:

function choose_icon {
    # Return random icon.
    local icons=(
        /usr/share/icons/oxygen/22x22/emotes/face-embarrassed.png
        /usr/share/icons/oxygen/22x22/emotes/face-foot-in-mouth.png
        /usr/share/icons/oxygen/22x22/emotes/face-clown.png
        /usr/share/icons/oxygen/22x22/emotes/face-confused.png
        /usr/share/icons/oxygen/22x22/emotes/face-crying.png
        /usr/share/icons/oxygen/22x22/emotes/face-laugh.png
        /usr/share/icons/oxygen/22x22/emotes/face-laughing.png
        /usr/share/icons/oxygen/22x22/emotes/face-quiet.png
        /usr/share/icons/oxygen/22x22/emotes/face-raspberry.png
        /usr/share/icons/oxygen/22x22/emotes/face-sad.png
        /usr/share/icons/oxygen/22x22/emotes/face-sleeping.png
        /usr/share/icons/oxygen/22x22/emotes/face-smirk.png
        /usr/share/icons/oxygen/22x22/emotes/face-surprise.png
        /usr/share/icons/oxygen/22x22/emotes/face-uncertain.png
        /usr/share/icons/oxygen/22x22/emotes/face-wink.png
        /usr/share/icons/oxygen/22x22/emotes/face-worried.png
        /usr/share/icons/oxygen/22x22/emotes/face-yawn.png
        /usr/share/icons/oxygen/22x22/emotes/food-cake.png
        /usr/share/icons/oxygen/22x22/emotes/food-pizza.png
    )
    echo $(random_array_element icons)
}

choose_icon  # => "/usr/share/icons/oxygen/22x22/emotes/food-cake.png"

License usage

I want to copy this line to my script:

file_data="$(<"file")"

Should I now add LICENSE.md from the root of this repository to my snippet?

Examples return false positives for aliases and builtins

Of the three examples here only hash correctly reports if an executable is in the PATH. type -p and command -v both report success on aliases, builtins, etc.

type -P (capital P) does correctly report if an executable is in the PATH.

Perhaps this section could be reworded to make this distinction more clear?

Run function in the background

I saw that at the very bottom of the README there was a command to run files in the background, which is very handy. However, I was wondering if there is a way to also run a certain function in the background?

Not showing up on trending?

This repository has received 700~ stars in the last 1-2 weeks and yet it is no where to be found on GitHub's trending page. I don't know if this is somehow related to the large influx of Chinese users who have recently found this repository.

Can anyone else confirm or reproduce what I am seeing?

Source for prior star count (Wayback machine, see star count in "inspect element"):

current

Need help: for loop

Hey,
I was wondering that this is an infinite loop.
for((;;)){ echo hi;}

Can you explain me how bash interpret this?

Regards,
deltax

Regex [ Not an issue ] [ Help needed ]

Can we use bash regex to match on multiple lines ?

For ex,

hello: one
hello: 2
Something: four
random: file

I want to extract just hello lines without grep, this may sound unnecessary, but just finding a way for the curious mind. πŸ˜€

Edit: Obviously without running a loop

Do not recommend "$OSTYPE" instead of "uname"

  1. $OSTYPE is inconsistent between the shells and uname:

    image

  2. $OSTYPE contains a version suffix (see above) which requires a regexp to be stripped, whereas uname returns a plain string like Darwin or Linux.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.