bug-findutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Please advise work around or bug fix


From: Bob Proulx
Subject: Re: Please advise work around or bug fix
Date: Wed, 24 Mar 2021 23:43:17 -0600

Yuen, Kam-Kuen CIV USARMY DEVCOM SC (USA) via Bug reports for the GNU find 
utilities wrote:
> I am running the following command and the "ls" command gives error
> message that the file cannot be found.  The problem is that the
> filename has spaces as part of the filename.

In addition to everything Berny said (which was quite a bit!) let me
say that handling spaces in file names has caused a shift in thinking
about how command lines are constructed.  Your example is a very
traditional Unix example that works very good when the files do not
have whitespace.  But as you have found when they do have whitespace
then the model does not work.

But there are other ways that handle whitespace okay.

> The purpose is to find all files that exceeding file size of 1k.
> Filename might include spaces, special character like '
> 
> find . -size +1k -print | xargs ls -sd

Instead of using -print | xargs one can now use find only.  For
example did you know that find has a built-in -ls option?  The -ls
action in find is like "ls -dils".

    find . -size +1k -ls

In conjuction with other utilities and filters that may be enough to
solve your problem completely.  But if not then there are still other
ways too.

> 3)      When running "ls" command directly on the folder, the screen
> show  " ' " character surrounding the filename e.g. 'This is a Test
> Case With spaces in Filename.pdf'
>
> 4)      In the case the filename already has ' special character,
> the "ls" command shows the filename with double " around the
> filename e.g. " This is a Tester's File.pdf"

This quoting is due to the new incompatible quoting that the GNU ls
(and GNU stat) commands now produce.  I do not approve but they now
produce that type of quoted output.  I personally use the "ls -N"
option (by setting export QUOTING_STYLE="literal" in my .bashrc file)
so as to get the traditional behavior.

> 6)      Trying to use the -0 option with xargs but it complains the argument 
> line too long

Did you use xargs -0 with find's -print0?  This should work.

    find . -size +1k -print0 | xargs -r0 ls -1sd

> Can you advise How to handle filename with hidden character like '
> or space or to report file size of current and subdirectories

If the find -ls action is not sufficient:

    find . -size +1k -ls

Then I would use this following technique since it effectively exactly
answers the question you asked.  Try this:

    find . -size +1k -exec sh -c 'ls -1sd "$@"' sh {} +

This technique is described in the find manual but it is a little
subtle therefore I will try to explain it.

The -exec ... {} + part gathers up all of the arguments that will fit
into the command line and passes them to the command being executed
all at once.  That makes it very efficient.  Since find is a C program
and the arguments are being passed internal to the program then there
is no worry about splitty on whitespace.

The command being run in ``-exec sh -c 'ls -1sd "$@"' sh {} +'' is the
``sh -c 'ls -1sd "$@"' sh'' command and all of the file names are
arguments.  For example if there are three files it might be this.

    sh -c 'ls -1sd "$@"' sh file1 file2 file3

The ``sh -c'' part reads the commands from the command string which is
the first option argument.  When using the -c option then a command
name is a required next argument to set the command name.  The command
name will be displayed in a process listing using 'ps'.  Most
importantly though if the command name is not provided then the first
filename provide by find will be used as the command name and that
file will be missing!  In the above the second "sh" is the command
name.

    man sh

     sh -c [-aCefnuvxIimqVEbp] [+aCefnuvxIimqVEbp] [-o option_name] [+o 
option_name] command_string [command_name [argument ...]]

           -c               Read commands from the command_string operand
                            instead of from the standard input.  Special
                            parameter 0 will be set from the command_name
                            operand and the positional parameters ($1, $2,
                            etc.)  set from the remaining argument operands.

Note that in the synopsis above that if the command_string includes
arguments that a command_name must appear between them.  Let's explore
that with a couple of examples to show this in practice.

    $ sh -c 'echo args "$@"' one two three
    args two three

    $ sh -c 'echo args "$@"' sh one two three
    args one two three

Additionally I am adding the ls -1 option to always write only one
column of output.  Otherwise the result might be multiple columns and
if the file list is large enough some might be multiple columns and
some might not be due to the group of file name arguments and
multiple invocations of the command.  Therefore using ls -1 ensures
that the output is always consistely 1 column.

And with those pieces and that technique we end up with the following.

    find . -size +1k -exec sh -c 'ls -1sd "$@"' sh {} +

Which I think exactly answers your question.  But the technique is
very useful and general purpose.

Note that I thought Berny's suggestion of using du was actually
the superior solution. :-)

    du -at +1k

Bob



reply via email to

[Prev in Thread] Current Thread [Next in Thread]