Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm trying to find and move a whole bunch of folders on a linux box.

All the folders are named the same, so I am using echo $RANDOM to provide a random number to use for a folder name.

echo $RANDOM
does indeed output a random number every time is is run. However,
find . -type d -name .AppleDouble -exec mv \'{}\' \'/raid/data/Storage/AppleDouble/`echo $RANDOM` \;
uses the same "random" number for every folder, and as a result, only moves one folder.

I think the issue is that the $RANDOM is being evaluated immediately when find begins to run. How do I escape it so the value of $RANDOM is not evaluated until the -exec option begins to run (or what is a better way to do this)?

Note: I'm on busybox, so I can't really install anything.

share|improve this question
add comment

3 Answers

You are correct; you didn't quote it, so it's evaluated by the shell while building the find command line. -exec doesn't use bash normally, though, so if you single-quote it or escape the $ then it won't be expanded at all.

The solution is to invoke bash inside -exec:

find . -type d -name .AppleDouble -exec bash -c 'echo $RANDOM' \;
share|improve this answer
    
Where is the output going in that case? running it produces a lot of empty lines –  Fake Name Apr 27 '12 at 7:18
    
Also, I updated the question a bit. I'm trying to use `echo $RANDOM` as one of the arguments to another command. –  Fake Name Apr 27 '12 at 7:22
    
@FakeName Are you sure you are running that command exactly as given? It should work. –  jw013 Apr 27 '12 at 7:22
    
You said BusyBox, which makes me wonder if you're getting a usable bash under find. (If you're getting empty lines then you're getting the output but $RANDOM is unset; this I would expect of non-bash shells, in particular from BusyBox's own ash clone.) If you have a separate bash, try invoking it by full pathname so BusyBox won't be tempted to substitute its builtin ash; at least some versions of BusyBox I've seen on Android will do that substitution (annoying when I found an Android bash for my phone!) –  geekosaur Apr 27 '12 at 7:23
    
@jw013 - Yes, exactly as it's given. It produces empty lines. –  Fake Name Apr 27 '12 at 7:23
show 14 more comments

There are several problems with the command you're running.

mv \'{}\' \'/raid/data/Storage/AppleDouble/`echo $RANDOM`

`echo something` is equivalent to something (except when something contains some special characters, in which case the effect of the additional echo and command substitution usually makes things worse). So this is a complicated way of writing

mv \'{}\' \'/raid/data/Storage/AppleDouble/$RANDOM

The shell therefore passes three parameters to the find command for the part of the command line represented above: mv, '{}', and '/raid/data/Storage/AppleDouble/12345 where 12345 is a random value. Since the value of the RANDOM special variable is expanded by the shell before invoking find, all the commands executed by find will run with the same value. Note also that you have extra single quotes which will be parts of the file names — just drop them.

Since you want to expand $RANDOM in each invocation, you need to tell find to execute a shell which will execute mv, instead of having find execute mv directly.

find . -type d -name .AppleDouble -exec sh -c 'mv "$0" /raid/data/Storage/AppleDouble/$RANDOM' {} \;

Note that the probability of a collision in the random numbers is pretty high: $RANDOM only goes up to 215, so if you're copying more than 213 files, the probability that two files are copied to the same target is more than 50%. It is a very bad idea to use a random name in this context. Instead, use a name that is guaranteed to be distinct for every source file. One way to do this is to use a cryptographic hash of the source path:

find . -type d -name .AppleDouble -exec sh -c 'mv "$0" /raid/data/Storage/AppleDouble/$(echo "$0" | md5sum | cut -d " " -f 1)' {} \;
share|improve this answer
    
find . -type d -name .AppleDouble -exec bash -c ' echo "$0"' {} \; produces a number of empty lines, and then sh: -c: line 0: unexpected EOF while looking for matching `'' sh: -c: line 1: syntax error: unexpected end of file –  Fake Name Apr 30 '12 at 7:47
    
Note that the bash on this device (it's embedded) is pretty old - root@127.0.0.1:/raid/data/Storage# bash --version GNU bash, version 3.00.16(2)-release (i486-slackware-linux-gnu) Copyright (C) 2004 Free Software Foundation, Inc. –  Fake Name Apr 30 '12 at 7:48
    
Also, sh is symlinked to bash. –  Fake Name Apr 30 '12 at 7:49
    
Or just increment a counter. –  Keith Thompson Apr 30 '12 at 8:03
add comment
up vote 0 down vote accepted

I'm not too sure what the problem actually wound up being.

I eventually gave up, and wrote an external script to pass to find's -exec, and that seems to be working.

I'm not sure why I couldn't just put the whole command in one line. It seems there are some odd bugs in the version of busybox and bash I have (this is an old version of both. It's busybox 1.1.0, which is from 2006, and bash 3.00.16 which is of a similar age (I cannot find a bash release history)).

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.