Argument list too long?

Well, what now? We got the dreaded “argument list too long” error. What to do?

To explain the problem, let’s consider what the shell does (we won’t get into system calls, to make things simple). The shell (Bourne compatible shells, actually) will first scan the line typed in. One of the first things to do is to expand file globs. For example, the command:

ls a*

will be translated by the shell into:

ls andrew apple alex allen alfred almonzo august axel albert

(and so forth). If the expansion expands beyond the system limitations, then it cannot be processed and the error “argument list too long” results.

The limit could be the number of arguments or the number of characters; however, the fix is the same. The key is to get the list (usually files) out of the argument list and into something else – such as stdout. Once the overlong list is being sent via stdout, the command xargs can be used to place all of the items on the command line, observing all relevant limits as it goes (and as efficient as possible to boot).

There are a variety of quick answers which will all fail, because the argument list would remain too long:

ls a* >savefile.txt
for i in a* ; echo $i ; done
echo a*

However, all is not lost: there are a number of ways to get a long list of files into stdout; the most common is to use find:

find . -name "CACHE.DAT" | xargs ls -ld

This may not be possible, if the desired list of files doesn’t fit neatly into a find command.

Another possibility, related to the previous example, would be this:

ls -1 | sed '/^a/!d' | xargs ls -ld

Yet another possibility might be to use a language like Perl; since it does not scan and process the same way, it would work without limitations:

perl -e 'opendir(DIR, "."); @all = grep /^a/, readdir DIR; closedir DIR; print "@all\n";' | xargs ls -ld

I would only recommend using Perl or other such if you are quick and snappy with your knowledge of the language; otherwise, such a long line will have you looking things up repeatedly.

If the arguments are coming from a file, then things become even easier; instead of something like this:

ls -ld $(cat mylist)

You can simply use:

cat mylist | xargs ls -ld

Of course, any binary command can be used with xargs, not just ls.

11 thoughts on “Argument list too long?”

  1. In simple cases where the filenames do not have embedded spaces, you can get by with an “echo /path/to/files/*”.

    That will produce a space-delimited list of files.

    Also, any mention of using find with xargs should include info regarding using the find “-print0′ and xargs “-0 or –null” options which should eliminate problems with spaces, newlines or other special characters embedded in filenames.

    Tom

  2. Using echo /path/to/files/* seems like a good idea, except that will result in the error occuring again, as the shell will expand /path/to/files/* into a large number of arguments to echo – in this example, too many arguments.

    Secondly, the -print0 option to find and the -0 option to xargs are only valid for GNU find and GNU xargs; standard find and xargs have not have these in the past.

    Double-checking shows that HP-UX find does have a print0 option; xargs does not seem to have the -0 option.

    Probably best way to handle problem filenames in a non-GNU environment is to use a scripting language like Perl or Ruby to read the directories and then act on them.

  3. Sorry Dave, I wasn’t clear- I meant that “echo /path/to/files/*” could be used to feed xargs, as a simple alternative to find.

  4. I know this is WAY too late, but thought I might help others who hit this on a Google search(helped me!):

    I added this to my aliases, it is probably still limited, but it has worked everytime I’ve needed it:

    alias longls ‘echo \!* | sed “s/ /\n/g”‘

    basically: echo /path/to/files/*, and then all the spaces are turned into newlines

    one strange thing: doesn’t like to be redirected but you can pipe it to tee e.g. “… | tee

  5. Thanks for the info.

    I have 1 million files and I want to check 30000 files (i have the names of that files). For example, ls -lt 1 2 3 4. . . .30000 and redirect the output to a file with filenames and time. Can any one help.

      1. Not sure whether supported on “csh”, didn’t work on “tcsh” on a Linux box. This is probably more of a “bash” thing.

    1. Your question is very vague. Most modern shells should not report “for” as an unknown command; most likely you are using a shell-builtin command (like “for”) when you should be using a binary program instead.

      One example is for xargs: xargs takes a binary program as an argument, not “for” or other shell builtins.

Leave a comment