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.

Using Bash

So let's say I have a bunch of files randomly placed in a parent directory ~/src, I want to grab all the files matching a certain suffix and move (or copy) them to a ~/dist directory.

Let's assume for this purpose that all filenames have this naming convention:

<filename_prefix>.<filename_suffix>

I found out that this was a quick way to get all files with a particular filename_suffix and put them in a dist folder:

mkdir ~/dst
find source -name "*.xxx" -exec mv -i {} -t ~/dst \;

Now a step further... how can I use the output of find, in this case filename, and use the filename_prefix to generate a directory of the same name in ~/dist and then move (or copy) all the files with that prefix into the appropriate directory?

mkdir ~/dst
find source -name "*.xrt,*.ini,*.moo" -exec mv -i {} -t ~/dst \;

Essentially, how do I change the above command (or maybe use another command), to create a structure like this

(OUTPUT)

~/dist/people/people.xrt
~/dist/games/games.xrt
~/dist/games/games.moo
~/dist/games/games.ini
~/dist/monkeys/monkeys.ini
~/dist/monkeys/monkeys.xrt

from a directory tree like this?

(INPUT)

~/src/xrt/people.xrt
~/src/xrt/games.xrt
~/src/conf/games.ini
~/src/pack/monkeys.xrt
~/src/e344/games.moo
~/src/e344/monkeys.moo
~/src/en-us/monkeys.ini
share|improve this question
add comment

2 Answers

up vote 8 down vote accepted

It would be a hell to tell find what to do in this case.

Better use the shell:

for i in **/*.{xrt,ini,moo}; do
  FILE=$(basename "$i")
  DIR=~/dst/${FILE%.*}
  echo mkdir -p -- "$DIR"
  echo mv -i -t "$DIR" -- "$i"
done

Use shopt -s globstar to make the ** glob work (or use zsh!). And remove the echos later if the command prints what you want.

share|improve this answer
    
using bash is this the same? –  qodeninja Feb 6 '12 at 20:44
    
@codeninja shopt -s globstar, see my edit. If there are only two levels, you can use */*.* and the snippet will work in any shell. –  Gilles Feb 7 '12 at 0:40
add comment

cheating find command line:

find source -name "*.xrt,*.ini,*.moo" -exec env file={} bash -c 'base="$(basename "$file")";dir="dst/${base%.*}";mkdir -p "$dir";cp "$file" "$dir"' \;

actually a work around for calling bash script in find LOL.

=P

share|improve this answer
    
Guess what happens if there is a file which is called… happy rm -rf / ! This kind of code deserves a -1. –  Stéphane Gimenez Feb 7 '12 at 13:04
    
Your edit is not enough: let's say you cliked on a link and downloaded Yay" rm -rf / "Rox0r.avi, again there is like a problem… –  Stéphane Gimenez Feb 7 '12 at 13:22
    
(And there is no way to make this kind of substitution safe). –  Stéphane Gimenez Feb 7 '12 at 13:24
    
Ah maybe it's possible to do this differently. It seems that the following works: -exec bash -c 'command which uses "$1"' bash '{}' ';'. Well, it's quite pointless anyway. –  Stéphane Gimenez Feb 7 '12 at 13:26
    
@StéphaneGimenez done, bash is not the only thing to use. LOL –  yuyichao Feb 7 '12 at 13:30
show 1 more 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.