├── .travis.yml ├── LICENSE.md ├── README.md └── bin ├── arch ├── basename ├── cat ├── date ├── dirname ├── echo ├── env ├── expand ├── expr ├── false ├── head ├── hostname ├── locale ├── logname ├── printenv ├── printf ├── pwd ├── realpath ├── seq ├── tail ├── true ├── wc ├── whoami └── yes /.travis.yml: -------------------------------------------------------------------------------- 1 | language: bash 2 | sudo: required 3 | 4 | os: 5 | - linux 6 | 7 | install: 8 | # Install a custom version of shellcheck instead of Travis CI's default 9 | - scversion="latest" # or "v0.4.7", or "latest" 10 | - wget "https://storage.googleapis.com/shellcheck/shellcheck-${scversion}.linux.x86_64.tar.xz" 11 | - tar --xz -xvf "shellcheck-${scversion}.linux.x86_64.tar.xz" 12 | - shellcheck() { "shellcheck-${scversion}/shellcheck" "$@"; } 13 | 14 | script: 15 | - shellcheck -e SC2059 -e SC2244 bin/* 16 | # Check for lines longer than 80 chars. 17 | - if grep '.\{81\}' bin/*; then (exit 1); else (exit 0); fi 18 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2018 Dylan Araps 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bareutils 2 | 3 | A coreutils written in pure `bash`. 4 | -------------------------------------------------------------------------------- /bin/arch: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # arch in pure bash. 4 | 5 | printf '%s\n' "${MACHTYPE%%-*}" 6 | -------------------------------------------------------------------------------- /bin/basename: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # basename in pure bash. 4 | 5 | for file in "$@"; do 6 | file="${file%/}" 7 | printf '%s\n' "${file##*/}" 8 | done 9 | -------------------------------------------------------------------------------- /bin/cat: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # cat in pure bash. 4 | 5 | for file in "$@"; do 6 | [[ ! -f $file ]] && { 7 | printf '%s\n' "cat: $file: No such file or directory." >&2 8 | exit 1 9 | } 10 | 11 | printf '%s\n' "$(<"$file")" 12 | done 13 | -------------------------------------------------------------------------------- /bin/date: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # date in pure bash. 4 | 5 | date_format="$1" 6 | 7 | [[ ${date_format:0:1} == + ]] && 8 | date_format="${date_format/+}" 9 | 10 | printf "%($date_format)T\\n" 11 | -------------------------------------------------------------------------------- /bin/dirname: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # dirname in pure bash. 4 | 5 | for file in "$@"; do 6 | printf '%s\n' "${file%/*}/" 7 | done 8 | -------------------------------------------------------------------------------- /bin/echo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # echo in pure bash. 4 | 5 | echo "$@" 6 | -------------------------------------------------------------------------------- /bin/env: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # env in pure bash. 4 | 5 | mapfile -t envars < <(compgen -v) 6 | 7 | for var in "${envars[@]}"; do 8 | printf '%s=%s\n' "$var" "${!var}" 9 | done 10 | -------------------------------------------------------------------------------- /bin/expand: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # expand in pure bash. 4 | 5 | [[ ! -f $1 ]] && { 6 | printf '%s\n' "expand: $1: No such file or directory." >&2 7 | exit 1 8 | } 9 | 10 | file="$(< "$1")" 11 | printf '%s\n' "${file//$'\t'/' '}" 12 | -------------------------------------------------------------------------------- /bin/expr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # expr in pure bash. 4 | 5 | printf '%s\n' "$(($@))" 6 | -------------------------------------------------------------------------------- /bin/false: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # false in pure bash. 4 | 5 | exit 1 6 | -------------------------------------------------------------------------------- /bin/head: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # head in pure bash. 4 | 5 | while getopts ":n:" opt; do 6 | case $opt in 7 | n) max_lines="$OPTARG" ;; 8 | 9 | :) 10 | printf '%s\n' "option -$OPTARG requires an argument." >&2 11 | exit 1 12 | ;; 13 | 14 | ?) 15 | printf '%s\n' "error: -$OPTARG not a valid option." >&2 16 | exit 1 17 | ;; 18 | esac 19 | 20 | shift "$((OPTIND - 1))" 21 | done 22 | 23 | [[ ! -f $1 ]] && { 24 | printf '%s\n' "head: ${1:-null}: No such file or directory." >&2 25 | exit 1 26 | } 27 | 28 | mapfile -tn "${max_lines:-10}" file_data < "$1" 29 | printf '%s\n' "${file_data[@]}" 30 | -------------------------------------------------------------------------------- /bin/hostname: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # hostname in pure bash. 4 | 5 | : '\h' 6 | printf '%s\n' "${_@P}" 7 | -------------------------------------------------------------------------------- /bin/locale: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # locale in pure bash. 4 | 5 | locale_vars=( 6 | LANG 7 | LC_CTYPE 8 | LC_NUMERIC 9 | LC_TIME 10 | LC_COLLATE 11 | LC_MONETARY 12 | LC_MESSAGES 13 | LC_PAPER 14 | LC_NAME 15 | LC_ADDRESS 16 | LC_TELEPHONE 17 | LC_MEASUREMENT 18 | LC_IDENTIFICATION 19 | ) 20 | 21 | 22 | for var in "${locale_vars[@]}"; do 23 | printf '%s=\"%s\"\n' "$var" "${!var:-$LANG}" 24 | done 25 | printf '%s=%s\n' "LC_ALL" "$LC_ALL" 26 | -------------------------------------------------------------------------------- /bin/logname: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # logname in pure bash. 4 | 5 | : '\u' 6 | printf '%s\n' "${_@P}" 7 | -------------------------------------------------------------------------------- /bin/printenv: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # printenv in pure bash. 4 | 5 | [[ $1 ]] && { 6 | printf '%s\n' "${!1}" 7 | exit 0 8 | } 9 | 10 | mapfile -t envars < <(compgen -v) 11 | 12 | for var in "${envars[@]}"; do 13 | printf '%s=%s\n' "$var" "${!var}" 14 | done 15 | -------------------------------------------------------------------------------- /bin/printf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # printf in pure bash. 4 | 5 | printf "$@" 6 | -------------------------------------------------------------------------------- /bin/pwd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # pwd in pure bash. 4 | 5 | printf '%s\n' "$PWD" 6 | -------------------------------------------------------------------------------- /bin/realpath: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # realpath in pure bash. 4 | 5 | file="${1%/}" 6 | parent_dir="${file%/*}" 7 | 8 | [[ -f ${PWD}/${file##*/} ]] && { 9 | printf '%s\n' "${PWD}/${file##*/}" 10 | exit 0 11 | } 12 | 13 | cd "$parent_dir" &>/dev/null || exit 1 && 14 | printf '%s\n' "${PWD}/${file##*/}" 15 | -------------------------------------------------------------------------------- /bin/seq: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # seq in pure bash. 4 | 5 | [[ -z $1 ]] && { 6 | printf '%s\n' "seq: error: missing arguments." >&2 7 | exit 1 8 | } 9 | 10 | [[ $2 ]] && 11 | first="$1" 12 | 13 | [[ $3 ]] && 14 | increment="$2" 15 | 16 | last="${*: -1}" 17 | 18 | for ((i=${first:=1};i<=last;i+=${increment:=1})); { 19 | printf '%s\n' "$i" 20 | } 21 | -------------------------------------------------------------------------------- /bin/tail: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # tail in pure bash. 4 | 5 | while getopts ":n:" opt; do 6 | case $opt in 7 | n) max_lines="$OPTARG" ;; 8 | 9 | :) 10 | printf '%s\n' "option -$OPTARG requires an argument." >&2 11 | exit 1 12 | ;; 13 | 14 | ?) 15 | printf '%s\n' "error: -$OPTARG not a valid option." >&2 16 | exit 1 17 | ;; 18 | esac 19 | 20 | shift "$((OPTIND - 1))" 21 | done 22 | 23 | [[ ! -f $1 ]] && { 24 | printf '%s\n' "tail: ${1:-null}: No such file or directory." >&2 25 | exit 1 26 | } 27 | 28 | mapfile -tn 0 file_data < "$1" 29 | 30 | [[ ${max_lines:=0} -gt "${#file_data[@]}" ]] && 31 | max_lines="${#file_data[@]}" 32 | 33 | printf '%s\n' "${file_data[@]: -$max_lines}" 34 | -------------------------------------------------------------------------------- /bin/true: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # true in pure bash. 4 | 5 | exit 0 6 | -------------------------------------------------------------------------------- /bin/wc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # wc in pure bash. 4 | 5 | while getopts "lcw" opt; do 6 | case $opt in 7 | l) lines=1 ;; 8 | c) bytes=1 ;; 9 | w) words=1 ;; 10 | 11 | ?) 12 | printf '%s\n' "error: -$OPTARG not a valid option." >&2 13 | exit 1 14 | ;; 15 | esac 16 | done 17 | 18 | [[ -t 0 && -f ${*: -1} ]] && 19 | file=${*: -1} 20 | 21 | [[ -t 0 && ! -f $file ]] && { 22 | printf '%s\n' "wc: ${file:-null}: No such file or directory." >&2 23 | exit 1 24 | } 25 | 26 | mapfile file_data < "${file:-/dev/stdin}" 27 | 28 | for line in "${file_data[@]}"; do 29 | read -ra line_split <<< "$line" 30 | ((splits+=${#line_split[@]}, chars+=${#line})) 31 | done 32 | 33 | [[ -z $lines && -z $bytes && -z $words ]] && 34 | ((lines=1, bytes=1, words=1)) 35 | 36 | [[ $lines ]] && printf '%s ' "${#file_data[@]}" 37 | [[ $words ]] && printf '%s ' "$splits" 38 | [[ $bytes ]] && printf '%s ' "$chars" 39 | 40 | printf '%s\n' "$file" 41 | -------------------------------------------------------------------------------- /bin/whoami: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # logname in pure bash. 4 | 5 | : '\u' 6 | printf '%s\n' "${_@P}" 7 | -------------------------------------------------------------------------------- /bin/yes: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # yes in pure bash. 4 | 5 | for ((;;)); { 6 | printf '%s\n' "${1:=y}" 7 | } 8 | --------------------------------------------------------------------------------