Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Hi this may be a very newbie question, but why doesnt the xargs /bin/ls work in this case? I thought it was supposed to be faster? Also what are those /fd/3 directories?

sh-3.2# find / -name 'GOALS*' -exec ls -l {} \;
find: /dev/fd/3: Not a directory
find: /dev/fd/4: Not a directory
.... This returns me the expected result....

However this returns the whole list of files in the directory

sh-3.2# find / -name GOALS* -type f | xargs /bin/ls -l

I am on a MacOS.

share|improve this question
    
You appear to be missing quotes around the wildcard in your second example. –  Nicole Hamilton Nov 17 '12 at 15:30
    
that doesnt help either. thanks though. –  kunj2aaan Nov 17 '12 at 16:55
add comment

3 Answers

1) you need to quote the * in the second find command,

2) the /dev/fd/* are devices which corresponds with stdin, stdout, stderr etc. thouse devices are simlinked and are different for each process,

3) the -type f says, the result has to be regular file, thus the /dev/fd/* are not in the result as they are block devices,

4) the xargs ls -l does the same as your ls -l {}... I even doubt the better performance in this case, but xargs is smarter and there are reasons to use it, eg. correct handling of files with whitespaces inside it,

If you are debugging the second version of your find, first of all see the output w/o the | xargs ls -l part

share|improve this answer
add comment

Your first command executes a new ls command for every filename which matches the name you provided. This includes directories, symbolic links, devices, and anything else that can be found. The ls command gets executed as files are found, so you will see listings as the files are found.

The second command only matches file with the specified name. Because you did not quote GOALS*, if you run from a directory with a matching entry, it will replace the GOALS* entry in the command. xargs calls ls will a long list of file names. You won't see results until either the find finishes, or a sufficiently long list of matches is found. Because of parsing rules filename which contain whitespace will cause problems.

These three commands should be equivalent for file without white space in the name. The third option does not work on all operating systems, but handles white space in the name.

find / -name 'GOALS*' -type f -exec ls -l {} \;
find / -name 'GOALS*' -type f | xargs /bin/ls -l
find / -name 'GOALS*' -type f -print0 | xargs -0 /bin/ls -l
share|improve this answer
add comment

The shell (bash) builtin exec replaces the current shell with the given argument. Try exec sleep 1, for example. The executable xargs is part of the GNU findutils package. It will execute the command given to it as the first argument with argument read from standard input.

E.g.:

$ echo -e "calves drink milk\npeople eat cows" | xargs -L1 cowsay
 ___________________
< calves drink milk >
 -------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
 _________________
< people eat cows >
 -----------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

The example you provided "does not work" because the argument list consisting of all files on your computer and special files under /sys and /proc grow too large. You cannot ask a command to work on arbitrarily large list of arguments because there is a limit (getconf ARG_MAX -- bytes I think).

Sometimes, you do want to do something with a large list of arguments though, and a solution is to process chunks of the list and not the whole list at once.

E.g.:

$ cat tmp/moo.sh
#!/bin/sh
echo processing $# arguments

$ seq 0 10000 | xargs -L 1001 sh tmp/moo.sh  | cat -n
     1  processing 1001 arguments
     2  processing 1001 arguments
     3  processing 1001 arguments
     4  processing 1001 arguments
     5  processing 1001 arguments
     6  processing 1001 arguments
     7  processing 1001 arguments
     8  processing 1001 arguments
     9  processing 1001 arguments
    10  processing 992 arguments

The last part of your question about "those fd" folders is about file descriptors. When you run find, it will look in /proc and see file descriptors (standard input, standard out, regular files for reading and writing) of running processes. By the time find exits and xargs takes over, some of those processes may no longer exist. Thus the errors. Files in /dev/fd are actually only symlinks:

$ ll /dev/fd/
total 0
lrwx------ 1 jaroslav jaroslav 64 Nov 18 01:57 0 -> /dev/pts/7
lrwx------ 1 jaroslav jaroslav 64 Nov 18 01:57 1 -> /dev/pts/7
lrwx------ 1 jaroslav jaroslav 64 Nov 18 01:57 2 -> /dev/pts/7
lr-x------ 1 jaroslav jaroslav 64 Nov 18 01:57 3 -> /proc/21677/fd
geee: ~
$ file /dev/pts/7
/dev/pts/7: character special
geee: ~
$ sudo echo "MOOOOOOO" >>  /dev/pts/7
Password:
MOOOOOOO

What I did there is I wrote to the standard output of my terminal. I have no idea what process 21677 is, but by the time find / finishes, I'm sure it will be destroyed even if it were present at the time when find scanned /proc.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.