patternbashMinor
An attempt at making a neat ls
Viewed 0 times
neatmakingattempt
Problem
This is a simple script to make ls output first folders, then files, then other stuff (symlink). I think this is really neat and would like to share the script in exchange for comments.
It should be noted that I'm working with GNU findutils and coreutils.
Some basic criteria that I'm aiming for include:
-
the output must not be prefixed with "./"
Problems:
Script
``
if [ ${#array[@]} -eq 0 ];then return 1 ;fi
if [ ${#array[@]} -eq ${#arrayLess[@]} ];then return 1 ;fi
if [ ${#array[@]} -lt ${#arrayLess[@]} ];then return 1 ;fi
return 0
}
# d dir f file p named pipe (FIFO) l sylink s socket D door (Solaris)
# c character (unbuffered) special b block (buffered) special
function finddirs {
find "$@" \
-maxdepth 1 -depth -type d \
-regextype gnu-awk -regex "$REGEX" \
-printf '%f\0'
}
function findfiles {
find "$@" \
-maxdepth 1 -depth -type f \
-regextype gnu-awk -regex "$REGEX" \
-printf "%f\0"
}
function findspecials {
find "$@" \
-maxdepth 1 -depth \( -type l -o -type p -o -
It should be noted that I'm working with GNU findutils and coreutils.
Some basic criteria that I'm aiming for include:
- lssort must accept the same arguments as ls
- lssort should depend on
bash,find,lsandxargs
-
the output must not be prefixed with "./"
Problems:
- arguments can not be augmented (-CFXtrs does not work)
Script
``
#! /bin/bash
#source $HOME/.scripts/string_manipulation.mergeme
function trim {
local var="$@"
#$ var=" hello space "
#$ echo ">"
#$ >
var="${var#"${var%%[![:space:]]*}"}" # rm leading whitespace characters
var="${var%"${var##*[![:space:]]}"}" # rm trailing whitespace characters
echo -n "$var"
}
function arrayContains {
# remove the shortest needle from array and compare lengths
# needs more testing...
declare -a array
declare -a arrayLess
declare needle
array=( "${!1}" ); shift # expand the passed array name
needle="$@" # try to match the rest as a string
arrayLess=( trim "${array[@]#${needle}}"` ) # remove value $needleif [ ${#array[@]} -eq 0 ];then return 1 ;fi
if [ ${#array[@]} -eq ${#arrayLess[@]} ];then return 1 ;fi
if [ ${#array[@]} -lt ${#arrayLess[@]} ];then return 1 ;fi
return 0
}
# d dir f file p named pipe (FIFO) l sylink s socket D door (Solaris)
# c character (unbuffered) special b block (buffered) special
function finddirs {
find "$@" \
-maxdepth 1 -depth -type d \
-regextype gnu-awk -regex "$REGEX" \
-printf '%f\0'
}
function findfiles {
find "$@" \
-maxdepth 1 -depth -type f \
-regextype gnu-awk -regex "$REGEX" \
-printf "%f\0"
}
function findspecials {
find "$@" \
-maxdepth 1 -depth \( -type l -o -type p -o -
Solution
- If you use
getoptorgetoptsto parse the options, you can use multiple options together, and it would simplify your code quite a bit. Example.
- When you create arrays explicitly (
name=(values)) you don't need todeclareit first.
arrayContainsshould take oneneedleand then the contents of the array in question. This is how it works in other languages, and is easier to program and more explicit than using an array reference and concatenated needles. Also, when expandingneedlethe values will be concatenated with a space between them, which is rather arbitrary.
- If
needleis empty,arrayContainsshouldreturn 0regardless of the array contents.
-
You can merge the
if statements in arrayContains by separating them with -o:if [ $a -eq 0 -o $b -eq 0 -o $c -eq $a ]-
ls works with globs rather than regular expressions by default. The find* functions will not return the same filenames as ls with the same input. For example, run touch example && mkdir eclectic and comparels [e]*with
find . -maxdepth 1 -depth -type f -regextype gnu-awk -regex "[e]*"- You should be able to get the current working directory with
$PWDrather thanpwdto save a fork. This makes the code a tiny bit faster, without losing clarity, and fixes a very common but little known bug: The `commandconstruct (identical to the preferred$(command)when using Bash) removes newlines from the end of the command output. That means if youmkdir $'foo\n' && cd $'foo\n',ORIGIN_DIR="pwd"will give the wrong result, butORIGIN_DIR="$PWD"will give the right one.
- Use More Quotes, for example do ARG="$1"
to enable working with whitespace in filenames. This is a very tricky subject.
- If you want to get this working with all filenames, you'll need to use an array to store the find
results before sending them tols`
Code Snippets
if [ $a -eq 0 -o $b -eq 0 -o $c -eq $a ]find . -maxdepth 1 -depth -type f -regextype gnu-awk -regex "[e]*"Context
StackExchange Code Review Q#15627, answer score: 2
Revisions (0)
No revisions yet.