From 1dfda10ddca1025c22fee1b3dda7dcd1b6439b78 Mon Sep 17 00:00:00 2001 From: Lea Date: Fri, 4 Jul 2025 16:07:49 +0200 Subject: [PATCH] First versions of the binaries and source file. --- calm | 37 +++++ cdz | 83 +++++++++++ daisy.source | 394 +++++++++++++++++++++++++++++++++++++++++++++++++++ editx | 27 ++++ filewait | 8 ++ newday | 52 +++++++ own | 4 + short | 19 +++ shrc | 47 ++++++ sw | 42 ++++++ what | 29 ++++ 11 files changed, 742 insertions(+) create mode 100755 calm create mode 100755 cdz create mode 100755 daisy.source create mode 100755 editx create mode 100755 filewait create mode 100755 newday create mode 100755 own create mode 100755 short create mode 100755 shrc create mode 100755 sw create mode 100755 what diff --git a/calm b/calm new file mode 100755 index 0000000..57f34e0 --- /dev/null +++ b/calm @@ -0,0 +1,37 @@ +#!/bin/bash +#LACKSETUP +# Calm a process down +# NEEDS_WORK: cleanup +# calm == only one process +# calm == all processes that match query +# calm * == if used in proc or a folder with just PID files, if not you will get an error +# calm .... OK +# set's NICE value to 0 +# need sudo +PIDS=$@ +errorFn() +{ + echo calm: Invalid operation or no such PID/process \(\"$(echo "$PIDS" | tr '\n' ' ' | cut -c -20)...\"\) + exit +} + +for pid in $PIDS +do + # Process to PID in elegant way + NEWPIDS=$(pidof "$pid") + if [ "$NEWPIDS" ] + then + BINNY=$pid + pid=$NEWPIDS + else + NEWBINS=$pid + BINNY=$(ps -p "$pid" -o comm= 2>/dev/null ) + if [ $? != 0 ] + then + errorFn + fi + fi + + echo Calming down $pid \("$BINNY"\)... + sudo renice -n 0 -p $pid; +done diff --git a/cdz b/cdz new file mode 100755 index 0000000..170076c --- /dev/null +++ b/cdz @@ -0,0 +1,83 @@ +#!/bin/bash + +if [[ $DAISY_INTERNAL -ne 1 ]]; +then + DAISY_INTERNAL=1 source $DAISY_SOURCE_FILE +fi + +target=$1 + +# Check if file exists +if [[ -z "$target" ]]; +then + echo "No target specified." + exit 1 +fi + +if ! test -f "$target"; +then + echo "File not found: \"$target\"" + exit 2 +fi + +file "$target" 1>/dev/null +exitcode=$? +report=$(file "$target") + +# Check for archive type, supported types are zip/tar/rar +comm1=(:) +comm2=(echo "Unsupported archive type$add: \"$target\"") +comm3=(:) + +echo $report | grep "tar archive" 1>/dev/null +istar=$? +echo $report | grep "Zip archive" 1>/dev/null +iszip=$? +echo $report | grep "RAR archive" 1>/dev/null +israr=$? + +# TAR archives come in many forms, if none of our tests say it's tar +# ...but it looks like tar and barks like tar, let's take the shot. +# Seems to work fairly well for the record. +RES=$(echo "$target" | grep ".tar") +if [[ RES != "" ]]; +then + istar=0 +fi + +# Now we set the right command +if (( istar == 0 )); then + comm2=(tar xvf "$target" -C) +elif (( iszip == 0 )); then + which unzip 1>/dev/null + exitcode=$? + if (( exitcode == 0 )); then + comm2=(unzip -q "$target" -d) + else + comm1=(echo "The utility 'unzip' is missing, please install it") + comm3=(exit 1) + fi +elif (( israr == 0 )); then + which unrar 1>/dev/null + exitcode=$? + if (( exitcode == 0 )); then + comm2=(unrar -i nul "$target") + else + comm1=(echo "The utility 'unrar' is missing, please install it") + comm3=(exit 1) + fi +fi + +# Create the temp dir, usually +dir=$(mktemp -d /tmp/extracted.XXXXXXXX) + +# And the rest of the commands +"${comm1[@]}" +"${comm2[@]}" $dir +"${comm3[@]}" + +cd $dir +echo "" +echo "Type 'exit' to exit the extracted archive's folder and auto-delete it" +eval $SHELL +rm -rf $dir diff --git a/daisy.source b/daisy.source new file mode 100755 index 0000000..67a5c10 --- /dev/null +++ b/daisy.source @@ -0,0 +1,394 @@ +#!/bin/echo "This file can only be sourced, not run stand-alone." -- #!/bin/bash +# LACKADAISICAL SOURCE-ABLE FILE + +# Source this in your RC file or manually to receive some of the simpler +# utilities, as well as aliases for `shrc` and `cdf`. Set env variable +# FROM_RC to 1 when sourcing this file to get RC-related functionality: +# FROM_RC=1 source /daisy.source +`` +# This file is also sourced in some of the scripts included within +# lackadaisical for common functionality. Some of the shared functionality is +# only included if sourced from one of the included scripts, though you are +# free to bypass this by setting env variable DAISY_INTERNAL to 1. + +[[ $DAISY_INTERNAL -eq 1 ]] && export DAISY_BIN=$(basename $0) + +# Intro function +function daisy_help() +{ + OLD_IFS="$IFS" + IFS= + echo -e "===================================================================" + echo -e "" + echo -e "Thanks for installing LACKADAISICAL!" + echo -e "This project aims to provide useful utilities as well as learning" + echo -e "material." + echo -e "It is still under heavy development, not all of the things on this" + echo -e "list are present/implemented." + echo -e "" + echo -e "===================================================================" + echo -e "" + echo -e "This suite provides a number of functions, aliases and scripts." + echo -e "They are all aimed at enhancing your efficiency." + echo -e "" + echo -e "===================================================================" + echo -e "" + echo -e "These are the included binaries:" + echo -e " - calm: Reduce a process niceness to 0." + echo -e " - chroot-aio: A chroot wrapper that also takes care of binding" + echo -e " every required directory and has no options." + echo -e " - cdz: This utility extracts an archive to /tmp and changes" + echo -e " directory to it in a new shell instance. Upon exit," + echo -e " the files are wiped." + echo -e " - editx: Uses your standard CLI editor to create/modify a" + echo -e " file and make it executable." + echo -e " - filewait: This tool is given a filename of a file that does" + echo -e " not exist yet. When the file appears on disk, the" + echo -e " program quits and simply returns the filename. This" + echo -e " can be used in personal workflows." + echo -e " - newday: A basic but powerful journaling system. Recommended" + echo -e " to set up via crontab. Can be used for everything" + echo -e " from diaries to BTRFS snapshots." + echo -e " - own: A simple utility. It effectively uses chown -R" + echo -e " user:user on its target. Root permissions required!" + echo -e " - short: This tool allows you to set up directory shortcuts." + echo -e " It enhances cd t to integrate itsef using its own" + echo -e " syntax. It is similar to wd." + echo -e " - shrc: This tool allows you to edit the RC file for your" + echo -e " shell in your preferred editor. After saving, the" + echo -e " file is sourced by your shell." + echo -e " - sw: A basic function that swaps two files by content." + echo -e " Useful for restoring backups." + echo -e " - what: This is a tool similar to which and others, the key" + echo -e " difference is that it returns partial matches. It can" + echo -e " be used to search for binaries." + echo -e "" + echo -e "===================================================================" + echo -e "" + echo -e "There are aliases and functions included within this file as well:" + echo -e " - bak/unbak: These small utilities make backups of files by making" + echo -e " a copy with a .bak suffix. Unbak reverses the process" + echo -e " using sw and removes the backup." + echo -e " - lsa: A simple alias for ls -lah." + echo -e " - lsn: A simple alias for ls -lah --sort=time --reverse." + echo -e " - editbin: An alias for editx $(which ). Saves on typing." + echo -e " - ched: Like chsh but for your editor (EDITOR env). A list" + echo -e " from which you can choose an installed editor" + echo -e " (CLI or GUI) is shown." + echo -e " - cdf: Use fzf to find a file and then cd to its location." + echo -e " - ldrc: Edits this file and source it, similarly to shrc." + echo -e " - daisy_init: Alias for directly sourcing this file from any" + echo -e " LACKADAISICAL binary. You may use this yourself." + echo -e " - daisy_cbin: Contains the name of the current LACKADAISICAL" + echo -e " binary being run." + echo -e " - daisy_enc: Converts a file/stdin to a base64 block that can be" + echo -e " decoded by passing the output(s) to daisy_dec." + echo -e " - *_multi: A version of daisy_enc that runs encodes multiple" + echo -e " files and outputs daisy_base64_data blocks to a file" + echo -e " or stdout." + echo -e " - daisy_dec: Converts daisy_base64_data blocks back to the form" + echo -e " it was in originally." + echo -e " - *_multi: A version of daisy_dec that runs on multiple input" + echo -e " blocks that are either stored in a file or stdin." + echo -e "" + echo -e "===================================================================" + echo -e "" + echo -e "To uninstall LACKADAISICAL, simply remove the source line from your" + echo -e "shell RC, and reload it. This does not remove the files!" + echo -e "" + echo -e "To read this notice again, call the function 'daisy_help'." + echo -e "" + echo -e "===================================================================" + + IFS="$OLD_IFS" +} + +# Variables for use in other utilities +# Find the right argument for our folder +ARG=$0 +if [[ ! $ARG == *daisy.source* ]]; +then + ARG="${BASH_SOURCE[0]}" +fi + +export DAISY_FOLDER=$(dirname $(realpath $ARG)) +export DAISY_SOURCE_FILE=$(realpath $ARG) +export DAISY_AVAILABLE=0 + +# Config folder setup +export DAISY_CONFIG_FOLDER="$HOME/.config/lackadaisical" +NEW_INSTALL=0 + +if [[ ! -d "$DAISY_CONFIG_FOLDER" ]]; +then + # Create the folder with its basics + mkdir -p "$DAISY_CONFIG_FOLDER" + echo "export EDITOR=$EDITOR" > "$DAISY_CONFIG_FOLDER/editor.src" + daisy_help + NEW_INSTALL=1 +fi + +# Installation into PATH +if [[ ! $PATH == *"$DAISY_FOLDER"* ]]; +then + export PATH="$PATH:$DAISY_FOLDER" + [[ NEW_INSTALL -eq 1 ]] && echo -e "Lackadaisical binaries have been added to your PATH variable." +fi + +# Load override from config (default is $EDITOR - so no change is made) +_EDITOR=$(cat "$DAISY_CONFIG_FOLDER"/editor.src | grep "EDITOR=" | sed 's/export EDITOR=//g') + +NEED_CHED=0 +if [[ -z $EDITOR ]]; +then + NEED_CHED=1 +fi + +# Never call if we're in internal mode +if [[ $DAISY_INTERNAL -eq 1 ]]; +then + NEED_CHED=0 +fi + +# Set up the basic alias for `shrc` +# Do not set these up if DAISY_INTERNAL=1 is set, or infinite recursion could +# occur! +if [[ ! -v DAISY_INTERNAL ]]; +then + alias shrc=". shrc" +fi + +############################################################################### +# FUNCTIONS and ALIASES ####################################################### +############################################################################### + +# bak and unbak +function bak() +{ + # Input: + target=$1 + + # Check if file exists + if ! test -f "$target"; + then + echo "Path not found: \"$target\"" + return 2 + fi + + # Handle both cases + if [[ UNBAK_MODE -eq 1 ]]; + then + cp -R "$target.bak" "$target" + rm -rf "$target.bak" + echo "Restored backup: $target <-- $target.bak" + else + cp -R "$target" "$target.bak" + echo "Backup made: $target --> $target.bak" + fi +} + +alias unbak="UNBAK_MODE=1 bak" +alias lsa="ls -lah" +alias lsn="ls -lah --sort=time --reverse" + +# Simple version of `cdf` +function cdf() +{ + cd $(dirname $(fzf)) +} + +# for convenience purposes +function editbin() +{ + editx $(which $1) +} + +# sets a new editor based on commony available ones, and some visual ones +function ched() +{ + editors=("nano" "vim" "nvim" "vi" "emacs" "gedit" "kate" "mousepad" "micro" \ + "code" "subl" "joe" "kwrite" "gnome-text-editor") + + # Find which editors are installed + available_editors=() + for editor in "${editors[@]}"; + do + EDITOR_REAL=$(which $editor) + if command -v "$EDITOR_REAL" >/dev/null 2>&1; + then + if [[ $(realpath "$EDITOR") == "$EDITOR_REAL" ]]; + then + available_editors+=("$editor (current choice)" "$EDITOR_REAL") + else + available_editors+=("$editor" "$EDITOR_REAL") + fi + fi + done + + if [[ ! -z $@ ]]; + then + TEXT="$@" + dialog --msgbox "$TEXT" 0 0 + fi + + # Present all choices + CHOICE=$(dialog --clear --title "Select Text Editor (Recommendation: nano)" \ + --menu "Choose one of the installed text editors:" 15 50 6 \ + "${available_editors[@]}" 3>&1 1>&2 2>&3) + DIALOG_RET=$? + + if [ $DIALOG_RET -ne 0 ]; + then + echo "No editor selected." + return + fi + + CHOICE=$(which $CHOICE) + echo export EDITOR=$CHOICE > "$DAISY_CONFIG_FOLDER/editor.src" + echo export DAISY_OLD_EDITOR=$EDITOR >> "$DAISY_CONFIG_FOLDER/editor.src" + + # Seems silly but this is also where we should export these + source "$DAISY_CONFIG_FOLDER/editor.src" +} + +function wait_for_editor() +{ + pname="$1" + fname="$2" + + # Give some time for a process to launch + sleep 1 + + while true; + do + ALIVE=$(ps aux | grep $fname | grep $pname) + if [[ $ALIVE == "" ]] + then + break + fi + sleep 1 + done +} + +function ldrc() +{ + FROM_RC=0 $EDITOR "$DAISY_SOURCE_FILE" + wait_for_editor $EDITOR "$DAISY_SOURCE_FILE" + source "$DAISY_SOURCE_FILE" +} + +function daisy_enc() +{ + has_file=$([[ ! -z $1 ]] && file $1 1>/dev/null; echo $?) + has_file=$([[ has_file -eq 0 ]] && echo 1) + file_info="no data" + file_name="null" + if [[ has_file -eq 1 ]]; + then + file_info=$(file $1) + file_name=$(basename $1) + fi + + data=$(cat ${1:-/dev/stdin}) + base64_inner=$(echo -e "$data" | base64 | tr '\n' '-') + + # Print out our block + printf "# File info: $file_info\n" + printf "daisy_data_base64_$file_name=\"$base64_inner\"" +} + +# Will only take input files, always outputs to stdout +function daisy_enc_multi() +{ + [[ ! -d $1 ]] && echo "daisy_dec_multi: No input files specified" && return + for file in "$@"; do + if [[ -f "$file" ]]; then + daisy_enc "$file" + echo # separate blocks with a newline + else + echo "daisy_enc_multi: Skipping non-file: $file" + fi + done +} + +function daisy_dec() +{ + data=$(cat ${1:-/dev/stdin} | sed -e 's/.*=\"//g' | grep -v "#" | tr -d '\"' | tr -d "'" | tr '-' '\n' ) + decoded=$(echo -e "$data" | cut -d "=" -f 1 | base64 --decode) + printf "$decoded" +} + +# Will only take a file and directory, sources it to find all encoded data +# Extracts to the directory +function daisy_dec_multi() +{ + [[ ! -f $1 ]] && echo "daisy_dec_multi: No input file specified" && return + [[ ! -d $2 ]] && echo "daisy_dec_multi: No output directory specified" && return + declare -a vars=( $(cat $1 | grep -v "# File") ) + for enc in "${vars[@]}"; + do + file=$(echo -e "$enc" | cut -d "_" -f 4- | cut -d "=" -f 1) + + if [[ ! "$file" == '' ]] + then + daisy_dec <(echo "$enc") | tee "$2"/"$file" + fi + done +} + +alias daisy_init='source "$DAISY_SOURCE_FILE"' + +############################################################################### +# end of FUNCTIONS and ALIASES ################################################ +############################################################################### +if [[ $NEED_CHED -eq 1 ]]; +then + # Editor is unset, pick one, set `vi` as backup + TXT1="There is no standard EDITOR environment variable defined. Choose one of the installed text editors." + TXT2="You can always change it later wih `ched`, part of the Lackadaisical suite." + ched $TXT1 $TXT2 +fi + +# End of user section! +export DAISY_AVAILABLE=1 + +# Start of internal section + +# Check for dependencies +function daisy_dependency_check() +{ + command -v $1 1>/dev/null 2>/dev/null; + res=$? + echo $(($res ^ 1)) +} + +DAISY_HAS_fzf=$(daisy_dependency_check fzf) +DAISY_HAS_md5sum=$(daisy_dependency_check md5sum) + +function daisy_quit_if_no() +{ + has_dep=$DAISY_HAS_$1 + + # Check first if we have checked for this dependency, if not, print a fixme! + # TODO: Remove upon release, or convert into self-modifying code. + if [[ ! -v DAISY_HAS_$1 ]]; + then + echo "FIXME: Dependency `$1` should have an env variable, checking ad-hoc" + has_dep=$(daisy_dependency_check $1) + fi + + if [[ $has_dep -eq 0 ]]; + then + echo "$DAISY_BIN: The dependency $1 was not found! Please install it" \ + "to be able to use this utility!" + exit 1 + fi +} + +[ -d "$DAISY_FOLDER" ] && export DAISY_AVAILABLE=1 + +# Source everything in the config folder +# We do this at the end so that we do not run into isues +for file in "$DAISY_CONFIG_FOLDER"/*; do + [ -f "$file" ] && source "$file" +done diff --git a/editx b/editx new file mode 100755 index 0000000..39e7810 --- /dev/null +++ b/editx @@ -0,0 +1,27 @@ +# !/bin/bash +# This utility pre-allocs a file and adds execution permissions. It also +# removes the resulting file if it is empty after the editor closes. + +if [[ -z $1 ]]; +then + echo "No filename specified." + exit 2 +fi + +if [[ -z "${EDITOR}" ]]; +then + ched "EDITOR env variable not set! You will have to set it yourself in the next screen." +fi + +exists=$(file "$1" >/dev/null && echo $?) + +touch "$1" +chmod +x "$1" +$EDITOR "$1" +wait $! +SIZE=$(du "$1" | cut -f 1) + +if [[ $SIZE -eq 0 && $exists -ne 0 ]]; +then + rm -rf "$1" +fi diff --git a/filewait b/filewait new file mode 100755 index 0000000..f00e554 --- /dev/null +++ b/filewait @@ -0,0 +1,8 @@ +#!/bin/bash +# A simple utility that waits for a file to become available, infinitely +FILE=$@ +while [ ! -f "$FILE" ] +do + sleep 0.1 +done +echo $FILE diff --git a/newday b/newday new file mode 100755 index 0000000..d6586f2 --- /dev/null +++ b/newday @@ -0,0 +1,52 @@ +#!/bin/bash +# This script is intended to be run via cron. + +# It creates a folder structure in home for the current date in the following format: +# $HOME/ByDate/// + +# It also sets up a symlink in home: $HOME/Today +# This symlink will always point to the folder for the current date. + +# Finally, it removes any folders without data, to prevent clutter. + +# - Why did you make this? +# I remember things better when they have a date attached to them. +# You can use this for a primitive form of note-taking, but aside from notes - +# you can store any data this way. + +BINSELF=$(basename $0) +DIR_NAME=ByDate +ROOT_DIR=$HOME/$DIR_NAME +TODAY_SYM=$HOME/Today + +# Present day +TODAY=$(date --iso-8601) +YEAR=$(echo $TODAY | awk -F"-" '{print $1}') +MONTH=$(echo $TODAY | awk -F"-" '{print $2}') +DAY=$(echo $TODAY | awk -F"-" '{print $3}') + +set -e + +function errorFn() +{ + ERROR=$? + if [[ $ERROR -gt 0 ]]; + then + echo "$BINSELF error ($ERROR): " + perl -E 'say $!=shift' $ERROR + fi + exit $ERROR +} + +# Error handling +trap errorFn ERR + +# First we clear out empty folders, and remove the symlink if it exists +test -e "$ROOT_DIR" && find "$ROOT_DIR" -maxdepth 3 -type d -empty -print | xargs rm -rf +test -L "$TODAY_SYM" && rm -rf "$TODAY_SYM" + +# Now we can set up today's directory +mkdir -p "$ROOT_DIR/$YEAR/$MONTH/$DAY" +cd $ROOT_DIR +ln -s "./$DIR_NAME/$YEAR/$MONTH/$DAY" "$TODAY_SYM" + diff --git a/own b/own new file mode 100755 index 0000000..bc030e3 --- /dev/null +++ b/own @@ -0,0 +1,4 @@ +#!/bin/sh +# Simple program that changes ownership to the current +# user, recursively. +sudo chown -R $(whoami):$(whoami) $1 diff --git a/short b/short new file mode 100755 index 0000000..d637e39 --- /dev/null +++ b/short @@ -0,0 +1,19 @@ +#!/bin/bash +# short: Creates shortcuts that can be used anywhere. +# Can also be used as an alternative for "alias". +# +# Example usage: +# Add a shortcut: short -A dev "/home/john/Development" +# Print shortcut content: short dev -> "/home/john/Development" +# Remove shortcut: short -D dev +# +# One could use this to do things like: +# cp -R files $(short dev) +# cd $(short www) +# ssh $(short server) +# +# Uses a file named .shortcuts in $HOME + +SHORT_FILE=$HOME/.shortcuts + + diff --git a/shrc b/shrc new file mode 100755 index 0000000..4c3342b --- /dev/null +++ b/shrc @@ -0,0 +1,47 @@ +#!/bin/echo Please run this program with: ". shrc" or include +# `FROM_RC=1 source shrc` in your RC file to set up an alias. + +# Just opens your .rc file easily, for your current shell +# and sources the .rc afterwards! + +# Source standard setup +if [[ $DAISY_INTERNAL -ne 1 ]]; +then + DAISY_INTERNAL=1 source $DAISY_SOURCE_FILE +fi + +function md5_opt() +{ + if [[ $DAISY_HAS_md5sum -eq 1 ]]; + then + echo $(md5sum "$1" | awk '{print $1}') + fi +} + +if [[ $FROM_RC -eq 1 ]]; then + alias shrc=". shrc" +else + BASENAME=$(basename $SHELL) + RC_NAME="."$BASENAME"rc" + RC_PATH="$HOME/$RC_NAME" + + # Optional MD5 checks + HAS_CHANGED=1 + SUM1=$(md5_opt "$RC_PATH") + SUM2= + + # This sets a default if the variable does not exist. + EDITOR=${EDITOR:-$(ched)} + $EDITOR "$RC_PATH" + wait_for_editor $EDITOR "$RC_PATH" + + SUM2=$(md5_opt "$RC_PATH") + + if [[ $DAISY_HAS_md5sum -eq 1 && "$SUM1" == "$SUM2" ]]; + then + echo "The RC-file $RC_NAME has not changed on disk. Not sourcing." + return + fi + + source "$RC_PATH" +fi diff --git a/sw b/sw new file mode 100755 index 0000000..6bf5cb5 --- /dev/null +++ b/sw @@ -0,0 +1,42 @@ +#!/bin/sh +# It just swaps two files +' +FILE1=$1 +FILE2=$2 + +function helpFn() +{ + ERROR=$? + if [[ $ERROR -gt 0 ]]; + then + echo "$BINSELF error ($ERROR): " + perl -E 'say $!=shift' $ERROR + fi + echo "Usage: $BINSELF " + echo Swap two files in a filesystem. + exit $ERROR +} + +if [[ $@ == *"--help"* ]]; +then + helpFn +fi + +# We set a trap here, together with 'set -e' above, +# this makes sure we exit gracefully if we have an +# error in one of the ls or mv calls. +trap helpFn ERR + +# We want to swap two files +# Easy, but let's be safe about it +ls "$FILE1" >/dev/null +ls "$FILE2" >/dev/null + +# Files should exist, now we move +mv "$FILE1" "$FILE1.sw" +mv "$FILE2" "$FILE2.sw" + +# We got our moved copies, now we simply rename +mv "$FILE1.sw" "$FILE2" +mv "$FILE2.sw" "$FILE1" + diff --git a/what b/what new file mode 100755 index 0000000..3df74d7 --- /dev/null +++ b/what @@ -0,0 +1,29 @@ +#!/bin/sh +# Where is the binary? +# Usage: what [] +# Returns: +# With no parameters, all visible binaries in PATH. +# With parameter, all binaries that match the pattern +# given. Accepts default grep patterns, case insensitive +# +# Examples: +# $ what zs.* +# pzstd +# zsh +# zstd +# +# $ what ftp +# ftppass +# sftp +# vsftpd +# +# $ what ftp | xargs which +# /usr/bin/ftppass +# /usr/bin/sftp +# /usr/sbin/vsftpd +# + +PWD=/ +ALL_BINS=$(cd / && echo $PATH | sed 's/[:]/ /g' | xargs ls -A | grep -v ":" | sort | uniq) +OUTPUT=$(printf '%s\n' "-n" $ALL_BINS | grep -i "$1") +echo "$OUTPUT"