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.

I have a document library where all of my files are in folders based on category name but then they are also all in subfolders called 'pdf' as well. Is there a way in bash to scan through all of the directories in the library and move all files in folders named pdf to their parent directory?

share|improve this question

2 Answers 2

up vote 2 down vote accepted

The following moves every file from a pdf folder into the parent directory.

find ~/some/folder -type d -name 'pdf' -print0 | while IFS= read -d '' dir
do
  find "$dir" -type f -maxdepth 1 -exec echo mv -- {} "$dir"/.. \;
done

Remove the echo once you're sure it does what you need.

Note that this will overwrite files without asking when the parent already contains one with the same name. Use mv -i to have it prompt you for confirmation before overwriting anything.

share|improve this answer
    
This worked! Thank you very much! –  portlandRyan May 3 '13 at 22:00
    
You're welcome. Since you asked for Bash tutorials: There are some common problems here, and some pitfalls, both on Greg's Bash Wiki – a really good resource. Also have a look at the Bash Hackers Wiki and the Advanced Bash Scripting Guide –  slhck May 4 '13 at 6:57

Here is what I thought of. Its not the prettiest thing, but it works to your specifications:

find . -ipath "*pdf/*.pdf" -type f -print0 | xargs -0 -I{} sh -c 'mv "{}" "$(dirname "{}")"/..'

It moves only .pdf files in pdf subfolders into their corresponding parent directories. To change the command to move all files in pdf subfolders, adjust the ipath argument to *pdf/*.


Example usage

$ find .
.
./category1
./category1/other_dir
./category1/other_dir/c1o1.txt
./category1/pdf
./category1/pdf/c1p1.pdf
./category1/pdf/c1p2.pdf
./category1/pdf/c1p3.pdf
./category2
./category2/other_dir
./category2/other_dir/c2o1.txt
./category2/pdf
./category2/pdf/c2p1.pdf
./category2/pdf/c2p2.pdf
./category2/pdf/c2p3.pdf

$ find . -ipath "*pdf/*.pdf" -type f -print0 | xargs -0 -I{} sh -c 'mv "{}" "$(dirname "{}")"/..'
.
./category1
./category1/c1p1.pdf
./category1/c1p2.pdf
./category1/c1p3.pdf
./category1/other_dir
./category1/other_dir/c1o1.txt
./category1/pdf
./category2
./category2/c2p1.pdf
./category2/c2p2.pdf
./category2/c2p3.pdf
./category2/other_dir
./category2/other_dir/c2o1.txt
./category2/pdf
share|improve this answer
2  
When piping from find to xargs, you should use find … -print0 | xargs -0 …. –  slhck May 3 '13 at 20:30
    
@slhck You are correct; thanks for pointing that out. Just updated my answer. –  Rain May 3 '13 at 20:34
    
Nice one with the ipath, didn't think about that. $(dirname $(dirname {})) can be abbreviated to "$(dirname {})"/.. if I'm not mistaken. (In general, the arguments {} should be quoted to prevent files with spaces in their name or similar from appearing as multiple arguments to mv.) –  slhck May 3 '13 at 20:51
    
Yep, just tested it; it works fine. "$(dirname {})"/.. makes it a lot cleaner, too. I didn't even think about quoting it, either. Any path with spaces would break the original command. –  Rain May 3 '13 at 20:57
    
You’re thinking DOS. In Unix (et. al.), *.* gets (only) all files whose names contain a period. To get all files, use just plain * (and even that might not get files whose names begin with a period). –  Scott May 3 '13 at 21:06

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.