Is there some elegant way to test/remove an empty directory?
Is there some elegant way to test/remove an empty directory?
Is there some elegant way to test/remove an empty directory?
Currently I am unconditionally doing rmdir "$dir" 2>/dev/null
where an empty directory will be removed, and the error message
in case of non-empty directories suppressed. It works, but that
way I suppress all error information which might have undesired
or undetected bad effects. So I was looking for some test based
approach like [[...]] && rmdir "$dir" but couldn't find simple
tests for that (e.g. -d and link count comparison isn't really
elegant either, the same with something like ls .* * 2>/dev/null
and string comparisons, or similar).
The rmdir(1) command is delegated to the rmdir(2) system call.
What would rmdir(2) do to determine the emptiness? Would we
have to do something similar/complex or am I missing something
obvious?
Janis
The rmdir(1) command is delegated to the rmdir(2) system call.
What would rmdir(2) do to determine the emptiness?
Would we
have to do something similar/complex or am I missing something
obvious?
Is there some elegant way to test/remove an empty directory?
Currently I am unconditionally doing rmdir "$dir" 2>/dev/null
where an empty directory will be removed, and the error message
in case of non-empty directories suppressed. It works, but that
way I suppress all error information which might have undesired
or undetected bad effects.
On 2022-06-13, Kaz Kylheku <480-992-1380@kylheku.com> wrote:
The rmdir implementation in a sufficiently Unix-like filesystem can just
look at the link count: an empty (non-root) directory has a link count
of exactly two: one is the "." self link, and the other is its name in
the parent (the thing being deleted).
I seemed to remember something like that, but a quick check shows
that a directory's link count is two plus the number of direct subdirectories.
Other contents, such as files, fifos or symlinks,
are not reflected in the link count.
The rmdir implementation in a sufficiently Unix-like filesystem can just
look at the link count: an empty (non-root) directory has a link count
of exactly two: one is the "." self link, and the other is its name in
the parent (the thing being deleted).
Of something else: namely that the directory link count is only
useful for knowing whether there are subdirectories, which is useful
for optimizing a recursive descent, in the case when you're only
looking for subdirectories.
Janis Papanagnou <janis_papanagnou@hotmail.com>:
Is there some elegant way to test/remove an empty directory?
I'm not sure: Does
{ test -d "$dir" && test -s "$dir" ; }
test for an empty directory? Then
Is there some elegant way to test/remove an empty directory?
Janis Papanagnou <janis_papanagnou@hotmail.com> writes:
Is there some elegant way to test/remove an empty directory?
Currently I am unconditionally doing rmdir "$dir" 2>/dev/null
where an empty directory will be removed, and the error message
in case of non-empty directories suppressed. It works, but that
way I suppress all error information which might have undesired
or undetected bad effects.
Depending on what rmdir you have, and what your portability requirements are, you might find that
rmdir --ignore-fail-on-non-empty "$dir"
does what you want.
One thing I am wondering, though, is; why isn't there a short form
of that option available? (There's plenty of free letters available
with the rmdir command.) The thought to mistype the long option, or
the necessity to call the man page and use the mouse to copy/paste
the exact text is not appealing for a shell programmer (concerning usability).
On 14.06.2022 at 08:57, Janis Papanagnou scribbled:
One thing I am wondering, though, is; why isn't there a short form
of that option available? (There's plenty of free letters available
with the rmdir command.) The thought to mistype the long option, or
the necessity to call the man page and use the mouse to copy/paste
the exact text is not appealing for a shell programmer (concerning
usability).
Why not create an alias or a shell function for it?
The schizophrenic thing in this case is that rmdir's other options
-v (--verbose), -p (--parents) have short and long form definitions
even though the long forms are rather short and easily memorizable
but the one with a pathological length (--ignore-fail-on-non-empty,
that's five word components!) has no short form. And I still wonder
why, what the designers think when doing that. If I'd want users to
*not* use a feature or option I'd certainly choose a name like that.
In article <t89nhn$1qva$1@gioia.aioe.org>,
Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:
...
The schizophrenic thing in this case is that rmdir's other options
-v (--verbose), -p (--parents) have short and long form definitions
even though the long forms are rather short and easily memorizable
but the one with a pathological length (--ignore-fail-on-non-empty,
that's five word components!) has no short form. And I still wonder
why, what the designers think when doing that. If I'd want users to
*not* use a feature or option I'd certainly choose a name like that.
The future trend, like it or not, is towards more and more longer options, some, as here, w/o short-form equivalents. I think the general feeling
among the developer community is that short (one letter) options are ambiguous and generally be avoided. They are retained mostly for
historical compatibility.
A good example of what can go wrong is this: For most programs, most of
the time, "-v" means "be verbose", which means it is A) generally a good
idea to include it, and b) safe to do so. But, in the "pkill" command,
"-v" means (basically) kill everything. Everybody gets bit by this at some point in their careers; this is why I think pgrep/pkill should be avoided.
It would be good to have a global, system-wide convention that "-v"
*always* means "be verbose" - always - and that it is always safe to
include it on the command line.
Finally, I don't understand your reluctance to use this long option (the 5 word one), since: A) It does exactly what you want (I was wrong to say
there was no non-kludgey answer to your question) and B) You are writing a script, right?, it is not like you have to type that out interactively.
Just put it in your script and be done with it.
In article <t89nhn$1qva$1@gioia.aioe.org>,
Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:
...
The schizophrenic thing in this case is that rmdir's other options
-v (--verbose), -p (--parents) have short and long form definitions
even though the long forms are rather short and easily memorizable
but the one with a pathological length (--ignore-fail-on-non-empty,
that's five word components!) has no short form. And I still wonder
why, what the designers think when doing that. If I'd want users to
*not* use a feature or option I'd certainly choose a name like that.
The future trend, like it or not, is towards more and more longer options, some, as here, w/o short-form equivalents. I think the general feeling
among the developer community is that short (one letter) options are ambiguous and generally be avoided. They are retained mostly for
historical compatibility.
Janis Papanagnou <janis_papanagnou@hotmail.com> writes:
Is there some elegant way to test/remove an empty directory?
Currently I am unconditionally doing rmdir "$dir" 2>/dev/null
where an empty directory will be removed, and the error message
in case of non-empty directories suppressed. It works, but that
way I suppress all error information which might have undesired
or undetected bad effects.
Depending on what rmdir you have, and what your portability requirements
are, you might find that
rmdir --ignore-fail-on-non-empty "$dir"
does what you want.
In article <t89nhn$1qva$1@gioia.aioe.org>,options,
Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:
...
The schizophrenic thing in this case is that rmdir's other options
-v (--verbose), -p (--parents) have short and long form definitions
even though the long forms are rather short and easily memorizable
but the one with a pathological length (--ignore-fail-on-non-empty,
that's five word components!) has no short form. And I still wonder
why, what the designers think when doing that. If I'd want users to
*not* use a feature or option I'd certainly choose a name like that.
The future trend, like it or not, is towards more and more longer
some, as here, w/o short-form equivalents. I think the general feeling among the developer community is that short (one letter) options are ambiguous and generally be avoided. They are retained mostly for
historical compatibility.
A good example of what can go wrong is this: For most programs, most ofat some
the time, "-v" means "be verbose", which means it is A) generally a good idea to include it, and b) safe to do so. But, in the "pkill" command,
"-v" means (basically) kill everything. Everybody gets bit by this
point in their careers; this is why I think pgrep/pkill should beavoided.
It would be good to have a global, system-wide convention that "-v"
*always* means "be verbose" - always - and that it is always safe to
include it on the command line.
Finally, I don't understand your reluctance to use this long option(the 5
word one), since: A) It does exactly what you want (I was wrong to saywriting a
there was no non-kludgey answer to your question) and B) You are
script, right?, it is not like you have to type that out interactively.
Just put it in your script and be done with it.
On 2022-06-13, Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:
The rmdir(1) command is delegated to the rmdir(2) system call.
What would rmdir(2) do to determine the emptiness?
I believe rmdir must be a dedicated primitive in each filesystem >implementation, including checking the necessary criteria.
Would we have to do something similar/complex or am I missing
something obvious?
GNU find has an -empty directive. This actually opens the
directory, and reads it until it finds an entry which is neither
"." nor "..". I suspect that is the only way which approaches 100% >portability across filesystems.
On 2022-06-13, Helmut Waitzmann <nn.throttle@xoxy.net> wrote:
Janis Papanagnou <janis_papanagnou@hotmail.com>:
Is there some elegant way to test/remove an empty directory?
I'm not sure: Does
{ test -d "$dir" && test -s "$dir" ; }
test for an empty directory?
Then
The -s test is documented for files. It probably checks the inode
st_size for zero. If it happens to work for a directory also, by
doing the same test, then that won't work because a directory is
never literally empty.do that for directories also, it won't work
because a directory is never literally empty.
I tried it on some emtpy and nonempty directories; it's always
succeeding (indicating non-empty).
By the way, it's inverted: a "test -s f" success means
that f is *not* empty.
Is there some elegant way to test/remove an empty directory?
Currently I am unconditionally doing rmdir "$dir" 2>/dev/null where an
empty directory will be removed, and the error message in case of
non-empty directories suppressed. It works, but that way I suppress all
error information which might have undesired or undetected bad effects.
So I was looking for some test based approach like [[...]] && rmdir
"$dir" but couldn't find simple tests for that (e.g. -d and link count comparison isn't really elegant either, the same with something like ls
.* * 2>/dev/null and string comparisons, or similar).
The rmdir(1) command is delegated to the rmdir(2) system call. What
would rmdir(2) do to determine the emptiness? Would we have to do
something similar/complex or am I missing something obvious?
Janis
On Mon, 13 Jun 2022 11:43:31 +0200, Janis Papanagnou wrote:
Is there some elegant way to test/remove an empty directory?
Currently I am unconditionally doing rmdir "$dir" 2>/dev/null where an
empty directory will be removed, and the error message in case of
non-empty directories suppressed. It works, but that way I suppress all
error information which might have undesired or undetected bad effects.
So I was looking for some test based approach like [[...]] && rmdir
"$dir" but couldn't find simple tests for that (e.g. -d and link count
comparison isn't really elegant either, the same with something like ls
.* * 2>/dev/null and string comparisons, or similar).
The rmdir(1) command is delegated to the rmdir(2) system call. What
would rmdir(2) do to determine the emptiness? Would we have to do
something similar/complex or am I missing something obvious?
Janis
With a two-stage delete, you have to be aware of the possible race
conditions (what is now, colloqually, known as "toctoa" or "time of
check to time of use"). A external file create may occur in the interval between the time that the check pronounces the directory "empty" and the delete attempts to delete it.
Similarly, an external file delete that
empties the directory may occur immediately after the check pronounces
the directory "not empty". None of the two-stage delete processes, either
by script, or by utility (like find(1)) accommodate this situation.
However, even though it is not "pretty", the rmdir(2) call (and the
rmdir(1) utility) perform an atomic test-and-delete.
Your best bet, IMHO,
is to suppress the rmdir(1) error reporting (such as has been suggested
with the GNU rmdir(1) --ignore-fail-on-non-empty option) and cope with
the inelegance of the solution. The alternatives are worse.
On 13.06.22 14:58, Ben Bacarisse wrote:
Janis Papanagnou <janis_papanagnou@hotmail.com> writes:
Is there some elegant way to test/remove an empty directory?
First, thanks to all for the suggestions and thoughts posted!
Currently I am unconditionally doing rmdir "$dir" 2>/dev/null
where an empty directory will be removed, and the error message
in case of non-empty directories suppressed. It works, but that
way I suppress all error information which might have undesired
or undetected bad effects.
Depending on what rmdir you have, and what your portability requirements
are, you might find that
rmdir --ignore-fail-on-non-empty "$dir"
does what you want.
This is indeed where I'd consider it best placed, as part of the
rmdir command - similar to the mkdir command with mkdir -p option.
(Would be nice if such an option gets standardized.) - Rethinking
about a separate test; this is probably not that good an idea for
my case, since I want to remove multiple directories and would want
to use shell patterns for that, like rmdir -option <date_pattern>
and individual tests would make a loop over the directory-list
necessary (which is also not an issue with a 'find'-based approach). Currently I am using that code in a GNU context only, so I can use
the suggested rmdir option.
One thing I am wondering, though, is; why isn't there a short form
of that option available?
Kaz Kylheku <480-992-1380@kylheku.com>:
On 2022-06-13, Helmut Waitzmann <nn.throttle@xoxy.net> wrote:
Janis Papanagnou <janis_papanagnou@hotmail.com>:
Is there some elegant way to test/remove an empty directory?
I'm not sure: Does
{ test -d "$dir" && test -s "$dir" ; }
test for an empty directory?
I'm sorry: I meant to test for an non‐empty directory.
Then
The -s test is documented for files. It probably checks the inode
st_size for zero. If it happens to work for a directory also, by
doing the same test, then that won't work because a directory is
never literally empty.do that for directories also, it won't work
because a directory is never literally empty.
I tried it on some emtpy and nonempty directories; it's always
succeeding (indicating non-empty).
That's too bad!
Is there some elegant way to test/remove an empty directory?
Currently I am unconditionally doing rmdir "$dir" 2>/dev/null
where an empty directory will be removed, and the error message
in case of non-empty directories suppressed. It works, but that
way I suppress all error information which might have undesired
or undetected bad effects. So I was looking for some test based
approach like [[...]] && rmdir "$dir" but couldn't find simple
tests for that (e.g. -d and link count comparison isn't really
elegant either, the same with something like ls .* * 2>/dev/null
and string comparisons, or similar).
The rmdir(1) command is delegated to the rmdir(2) system call.
What would rmdir(2) do to determine the emptiness? Would we
have to do something similar/complex or am I missing something
obvious?
Janis
On 15.06.22 12:03, Brian Patrie wrote:
Janis Papanagnou wrote:
Is there some elegant way to test/remove an empty directory?
[...]
In zsh:
rmdir *(D/^F)
So assuming that the directories to consider have week numbers as
names, and if I understand it correctly, that would work fine for
my case (i.e. also without the 'D') from any shell
zsh -c 'rmdir W[0-5][0-9](/^F)'
Janis Papanagnou wrote:
Is there some elegant way to test/remove an empty directory?
[...]
In zsh:
rmdir *(D/^F)
will (attempt to) remove all empty directories in the current directory.
* = glob (replace with the glob of your choice)
D = include dotfiles
/ = only directories
^ = not
F = directories with files
On 15.06.22 19:57, Janis Papanagnou wrote:
On 15.06.22 12:03, Brian Patrie wrote:
Janis Papanagnou wrote:
I spoke too soon. That will produce an error message in case nothingIn zsh: rmdir *(D/^F)So assuming that the directories to consider have week numbers as
names, and if I understand it correctly, that would work fine for my
case (i.e. also without the 'D') from any shell
zsh -c 'rmdir W[0-5][0-9](/^F)'
matches at the moment.
How can we control globbing in zsh for non-existing empty directories
to be not considered an error?
with <t8d76k$1bjp$1@gioia.aioe.org> Janis Papanagnou wrote:
On 15.06.22 19:57, Janis Papanagnou wrote:
On 15.06.22 12:03, Brian Patrie wrote:
Janis Papanagnou wrote:
*SKIP*
I spoke too soon. That will produce an error message in case nothingIn zsh: rmdir *(D/^F)So assuming that the directories to consider have week numbers
as names, and if I understand it correctly, that would work fine
for my case (i.e. also without the 'D') from any shell
zsh -c 'rmdir W[0-5][0-9](/^F)'
matches at the moment.
This might be A Good Thing(tm). Because you (plural) are doing
somehting wrong.
How can we control globbing in zsh for non-existing empty
directories to be not considered an error?
zsh -c 'rmdir W[0-5][0-9](N/^F)'
And see what is about to happen.
N (nullglob) will cause rmdir to get no args if there are no matches,
which will just yield a different error message. It could be done in a
for loop:
zsh -c 'for f in W[0-5][0-9](N/^F) ;do rmdir $f ;done'
which would also have the benefit of avoiding the dreaded "line too
long" error (at the expense of forking for each file).
The "no matches" error is, imho, desirable in an interactive situation.
But i'm gathering that this is a script situation, and that you don't
want it returning nonzero if there are no matches.
N (nullglob) will cause rmdir to get no args if there are no matches,
which will just yield a different error message. It could be done in a
for loop:
zsh -c 'for f in W[0-5][0-9](N/^F) ;do rmdir $f ;done'
which would also have the benefit of avoiding the dreaded "line too
long" error (at the expense of forking for each file).
Meanwhile, if you're going to require zsh, anyway, you might consider
just doing the whole script in zsh (though i understand if it's complex enough that you don't want to go chasing down bashisms or whatnot that
don't work in zsh).
On 18.06.2022 02:16, Brian Patrie wrote:
So what to do then? - Something like this...?
zsh -c 'set -o nullglob ; echo W[0-5][0-9](N/^F)' | xargs -r rmdir
if [ $# -gt 0 ] ; then
$command "$@"
if [ $# -gt 0 ] ; then
$command "$@"
else
true
fi
On 18.06.2022 02:16, Brian Patrie wrote:
The "no matches" error is, imho, desirable in an interactive
situation. But i'm gathering that this is a script situation,
and that you don't want it returning nonzero if there are no
matches.
N (nullglob) will cause rmdir to get no args if there are no matches,
which will just yield a different error message. It could be done
in a for loop:
zsh -c 'for f in W[0-5][0-9](N/^F) ;do rmdir $f ;done'
which would also have the benefit of avoiding the dreaded "line too
long" error (at the expense of forking for each file).
Meanwhile, if you're going to require zsh, anyway, you might consider
just doing the whole script in zsh (though i understand if it's
complex enough that you don't want to go chasing down bashisms or
whatnot that don't work in zsh).
Well, ksh'isms in my case. :-) A lot of ksh'isms seem to work in zsh.
There's some I don't want to transcribe, though.
So what to do then? - Something like this...?
zsh -c 'set -o nullglob ; echo W[0-5][0-9](N/^F)' | xargs -r rmdir
OTOH, i like Kaz's shell function approach, as it avoids the zsh
dependency; though you're then back to requiring rmdir to support
the --ignore-fail-on-non-empty option.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 498 |
Nodes: | 16 (2 / 14) |
Uptime: | 12:57:24 |
Calls: | 9,822 |
Calls today: | 1 |
Files: | 13,759 |
Messages: | 6,190,952 |