I’m writing script is ksh. Need to find all directory names directly under the current directory which contain only files, not subdirectories.
I know that I could use ls -alR and recursively parse output for the first letter in the first field (d for a directory). I think awk is the best way to parse and find.
For example, a simple ls -al output in the current directory:
drwxr-xr-x 22 af staff 748 18 Mar 22:21 . drwxr-xr-x 5 root admin 170 17 Mar 18:03 .. -rw------- 1 af staff 3 17 Mar 16:37 .CFUserTextEncoding drwxr-xr-x 5 af staff 170 17 Mar 17:12 Public drwxr-xr-x 9 af staff 306 18 Mar 17:40 Sites -rw------- 1 af staff 3 17 Mar 16:37 textd …
There are 2 directories in this output: Public and Sites. The directory Public doesn’t contain subdirectories, but Sites does. There are 3 subdirectories in Sites. So I need to echo only the directories which don’t contain directories in them. In my case, this is only Sites.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
If you are able to use find and if you are working on a “normal Unix filesystem” (that is, as defined in find(1) under -noleaf option description), then the following command can be used:
find . -type d -links 2
Each directory has at least 2 names (hard links): . and its name. Its subdirectories, if any, will have a .. pointing to the parent directory, so a directory with N subdirectories will have hard link count equal to N+2. Thus, searching for directories with hard link count equal to 2, we search for directories with N=0 subdirectories.
So, if you can use find, this is arguably the fastest method and obviously superior to in-shell loops over the directory contents stat()‘ing each of its members.
Method 2
*/ matches the subdirectories of the current directory. This includes symbolic links to directories, which you may or may not desire.
In ksh93, adding ~(N) at the beginning of the pattern makes it expand to the empty list if there is no match. Without this, the pattern remains unchanged if there is no match.
The following ksh93 function lists the subdirectories of the current directories that do not contain any subdirectory or link to a directory.
list_leaf_directories () {
local FIGNORE='.?(.)' # don't ignore dot files
local d
for d in */; do
[[ -L $d ]] || continue; # skip symbolic links
set -- ~(N)"$d"/*/
if ((!$#)); then echo "$d"; fi
done
done
Method 3
You don’t need to use awk at all. Use the built-in tests that ksh provides, something like this:
#!/bin/ksh
for NAME in *
do
FOUND=no
if [[ -d $NAME && $NAME != '.' && $NAME != '..' ]]
then
for SUBNAME in $NAME/*
do
if [[ -d $SUBNAME ]]
then
FOUND=yes
break
fi
done
if [[ $FOUND == no ]]
then
echo Found only files in $NAME
fi
fi
done
That little script looks in all the directories in the current directory, and tells you if they only contain files, no sub-directories.
Method 4
if I am not misunderstanding you, you only want to find files in the directory not the subdirectories. If this is your intention, here is the solution
find . -type f
if you want to find other than regular files (like block device files, character device files etc) then see the man page for find command and look for the type keyword on that page. You will see different filetypes, including regular files and directories etc.
Hope this is what you are looking for
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0