Reputation: 953
EDIT 2: For those with the same question, please be sure to read the comments on the accepted answer, as they go more in depth about how to properly use the command. I will post the final script once it is done with my own explanation of what is going on.
I'm trying to write a simple bash function that clears the terminal screen, then performs multiple ls
commands to show the different content types of the current directory in different colors.
I've managed to write something in Python which kind of does the same thing, but it has some big drawbacks (specifically, the behavior for special characters in filenames is "iffy" on Cygwin, and it's a pain to make it fit properly on the screen). I want it to look something like this:
*With non-dotfiles in green (haven't include them in the screenshot for privacy reasons).
I've managed to list both hidden directories and visible directories, but the files are giving me trouble. Every method of using ls
to get all files I've tried uses the -l
argument, or something like find
or grep
, all of which output the files in a single column (not what I want).
Is it possible to use the ls
command (or something else) to output only the files or dotfiles of a directory while keeping ls
's default output format?
EDIT 1: Here's what the script currently looks like (not much yet, but some people want to see it)
function test() {
clear;
GOLD=229;
RED=203;
BLUE=39;
WHITE=15;
GREEN=121;
# Colored legend.
tput sgr0;
tput setaf bold
# echo's "-n" suppresses the new line at the end.
tput setaf $GOLD;
echo -n "Working Directory ";
tput setaf $RED;
echo -n "Hidden Directories ";
tput setaf $BLUE;
echo -n "Visible Directories ";
tput setaf $WHITE;
echo -n "Hidden Files ";
tput setaf $GREEN;
echo "Visible Files";
pwd;
ls -d .*/; # List hidden directories.
ls -d */; # List visible directories.
# List dotfiles.
# List files.
}
Upvotes: 0
Views: 1558
Reputation: 953
Using the answer provided by matzeri, I managed to get a nice start. That answer is still accepted, because it answered the question that I asked. Here's the current version of the script, which I've turned into a function for easy access. I'm gonna go through it and explain some things that needed to be modified from the answer to give me the result I wanted, but didn't specifically ask for.
c() {
stty -echo; # Disable keyboard inputs during function.
local HAS_DOTDIRS=false;
local HAS_DIRS=false;
local HAS_DOTFILES=false;
local HAS_FILES=false;
local BLUE=39;
local GOLD=229;
local GREEN=121;
local PINK=170;
local RED=203;
local WHITE=15;
local CYG_CWD=$(pwd);
local WIN_CWD=$(cygpath -w "$(pwd)" | sed 's/\\/\//g');
local DOTDIRS=$(ls -Ad .*/); # Get directories with '.' prefix.
local DIRS=$(ls -Ad */); # Get normal directories.
local DOTFILES=$(find . -maxdepth 1 -type f -name ".*" | sed 's/^..//');
local FILES=$(find . -maxdepth 1 -type f -not -name ".*" | sed 's/^..//');
clear;
tput sgr0;
tput setaf bold;
local LEGEND="$(tput setaf $GOLD)Cygwin Working Directory ";
LEGEND+="$(tput setaf $PINK)Windows Working Directory ";
if ! [ -z "$DOTDIRS" ] ; then
HAS_DOTDIRS=true
LEGEND+="$(tput setaf $RED)Hidden Directories ";
fi
if ! [ -z "$DIRS" ] ; then
HAS_DIRS=true
LEGEND+="$(tput setaf $BLUE)Visible Directories ";
fi
if ! [ -z "$DOTFILES" ] ; then
HAS_DOTFILES=true
LEGEND+="$(tput setaf $WHITE)Hidden Files ";
fi
if ! [ -z "$FILES" ] ; then
HAS_FILES=true
LEGEND+="$(tput setaf $GREEN)Visible Files";
fi
echo $LEGEND;
echo "";
echo "$(tput setaf $GOLD)$CYG_CWD";
echo "$(tput setaf $PINK)$WIN_CWD";
tput setaf $RED
ls_list "$HAS_DOTDIRS" "$DOTDIRS"
tput setaf $BLUE
ls_list "$HAS_DIRS" "$DIRS"
tput setaf $WHITE
ls_list "$HAS_DOTFILES" "$DOTFILES"
tput setaf $GREEN
ls_list "$HAS_FILES" "$FILES"
tput sgr0;
stty echo; # Enable keyboard inputs after function.
}
ls_list() {
# $1 - boolean - condition to print
# $2 - list - names to 'ls'
if $1 ; then
echo "$2" | xargs -d '\n' ls -d;
fi
}
Firstly, I wrapped the whole thing with stty
to stop the user from messing-up the output with keyboard inputs.
Then, I create booleans that will allow the ls
outputs at the end to be performed with a very minimal delay between them (if [ bool ]
rather than checking the status of a list).
The color variables are simply used by the tput
command, which lets you change the color of the terminal's text.
Note: Some of the color values might be off, that's because I had issues with my Cygwin theme (currently using Nord), and these values look like their names on my setup. Your mileage may vary.
To fellow Cygwin users: I've had a few issues with tput
not working when it would've worked on an actual Linux machine. If you're having trouble with tput
consider defining the LS_COLORS
(which can be formatted to accept RGB values), and setting the CLICOLOR
variable to true, then exporting both. This can replace the tput
command, although you now might want to store the initial value of both, and you have to export the LS_COLORS
variable constantly.
The CYG_CWD
and WIN_CWD
are there because Cygwin paths aren't the same as Windows paths, and I like having both. The sed
command replaces Windows' "\" with "/" for easy copy+paste.
This is where the answer to the question starts. The DOTDIRS
, DIRS
, DOTFILES
, and FILES
variables will get lists.
The ls
command already allows us to filter just directories and directories starting with .
, via the ls -Ad */
and the ls -Ad *./
commands. ls
ignores files starting with .
, unless specified (like I do), ending with /
searches for directories, and the -d
parameter makes it name directories instead of showing us what's in them.
As for dotfiles and regular files, ls
doesn't really let us get them, because you can't specify a character which defines a file like you can with /
for directories. Instead, we can use the find . -maxdepth -type f
with the appropriate use of the -name
or -not -name
arguments to filter our files. There is an issue, however: the command will prefix the results with ./
. So .bashrc
becomes ./.bashrc
. I don't want that. The output is thus piped to the sed
command, which substitutes the first two characters for nothing (effectively removing them).
From here, we simply determine which list has elements, set the appropriate boolean values to ensure quick ls
outputs at the end, print the legend, all the while changing the colors the terminal uses with the tput
command.
Eventually, the ls_list
function is called. If the given boolean is true, it performs the echo "$2" | xargs -d '\n' ls -d
command. Essentially, it echoes the list of items found, which is piped into the xargs -d '\n'
command. xargs
allows us to pass the values piped to it as parameters for the ls
command. The -d '\n'
arguments changes the separator from spaces to newlines, because some names might have spaces in them. What ls
does, when you give it filenames, is simply prints them with the regular ls
output format (which is exactly what I want). I added the -d
parameter so that is names directories instead of showing their contents, since I'm using that function for all my lists.
Finally, reset whatever tput
is with sgr0
and re-enable keyboard inputs with stty
!
This is what the output looks like for my /home
directory.
Final notes:
It feels slightly slower than my Python script, but it won't bug-out with special characters in filenames and it will always respect the terminal's window size, since that's what ls
does. I think the "slowness" might be because the 4 xargs ls
operations don't print at the same time, while the python one printed everything at once. I can live with it being 1-2 seconds vs 0.5-1 second.
Upvotes: 0
Reputation: 602
For non-hidden files and directories, try
ls -d *
For hidden files and directories, use
ls -d .*
Upvotes: 0
Reputation: 8496
to list only the dot files in the current directory
find . -maxdepth 1 -type f -name ".*" | xargs ls --color=tty
to list only the other files
find . -maxdepth 1 -type f -not -name ".*" | xargs ls --color=tty
Upvotes: 1