Richard L
Richard L

Reputation: 119

IF test against ARG_MAX and number of files in directory

I have potentially a large number of generated files and subdirectories in a directory for which the number is not known ahead of execution. For simplicity, lets say I just want to invoke

mv * /another_dir/.

But for large numbers of files and subdirectories, it'll come back with the dreaded 'argument too long'. Yes I know find and xargs is a way to deal with it. But I want to test that number against ARG_MAX and try it that way first.

I'm on a Mac and so I can't up the ulimit setting.

So far I have

# max_value
if ((expr `getconf ARG_MAX` - `env|wc -c` - `env|wc -l` \* 4 - 2048)  ) ; then echo "ok" ; fi

which offers me a value to test against.

Lets say my test value to compute number of files or subdirectories in directory is based on

# test_value
(find . -maxdepth 1 | wc -l)

How can I get a working expression no matter how many files

if (test_value < max_value ) ; then echo "do this" else echo "do that" ; fi 

Every way I try to construct the if test, the syntax fails for some reason in trying to set the max_value and test_value parameters and then test them together. Grateful for help.

Upvotes: 0

Views: 185

Answers (1)

Gordon Davisson
Gordon Davisson

Reputation: 125948

When writing shell scripts, you have to pay a lot of attention to what context you're in, and use the right syntax for that context. The thing that goes between if and then is treated as a command, so you could use e.g. if expr 2 \> 1; then. But the modern replacement of the expr command is the (( )) arithmetic expression, so you'd use if (( 2 > 1 )); then. Note that you don't need to escape the > because it's no longer part of a regular command, and that you cannot put spaces between the parentheses ( ( something ) ) does something completely different from (( something )).

(( )) lets you run a calculation/comparison/etc as though it were a command. It's also common to want to use the result of a calculation as part of a command; for that, use $(( )):

max_value=$(($(getconf ARG_MAX) - $(env|wc -c) - $(env|wc -l) * 4 - 2048))
test_value=$(ls -A | wc -l)

Note that I used $( ) instead of backticks; it does essentially the same thing, with somewhat cleaner syntax. And again, the arrangement of parentheses matter: $(( )) does a calculation and captures its result; $( ) runs a command and captures its output. And $( ( ) ) would run a command in a pointless sub-subshell and capture its output. Oh, and I used ls -A because find . -maxdepth 1 will include . (the current directory) in its output, giving an overcount of 1. (And both the find and ls versions will miscount files with linefeeds in their name; oh, well.)

Then, to do the final comparison:

if ((test_value < max_value)) ; then echo "do this" else echo "do that" ; fi 

Upvotes: 1

Related Questions