3

Question

Assuming I have

dir 1/dir 2/file 1
dir 3/dir 4/file 2

(spaces in directory and file names are intentional)

I want to end up with

dir 1/file 1
dir 3/file 2

Related but incomplete answers

This answer moves all the files into the current parent directory (instead of each file's parent directory)

find . -maxdepth 1 -exec mv {} .. \;

This answer prints out each parent directory but I'm not sure how to do the moving.

find . -name '.user.log' | xargs -I{} dirname {}
asked Mar 23, 2017 at 3:49
1
  • echo $( find . -name '.user.log' | xargs -I{} dirname {} ) Commented Mar 24, 2017 at 1:52

3 Answers 3

7
find -type f -execdir mv "{}" ../ \;

The -execdir is like -exec but does its job in a directory where the particular file is, so the ../ part works as you need.

To get rid of empty dir2 and dir4 in your example you need another specialized command, but the main task is done.

answered Mar 23, 2017 at 5:34
0
0

for x in */* ; do [ -d $x ] && ( echo cd $x ; echo pwd ; echo mv * .. ; echo cd ../.. ) ; done

Like what you see? Then remove the word echo (from multiple locations)

Might not work in every case, e.g. if symbolic links are used. Tested with OpenBSD ksh (preliminary results looked good on manual visual inspection -- I did not remove echo commands).

Note that [ is a command ; it shares the same man page as test (although since it is an internal command for your shell, you'd want to use the man page for your shell and search for documentation on the command.)

answered Mar 23, 2017 at 4:39
5
  • 1
    shorter: for x in * ; do mv "$x"/*/* "$x"/ ; done Commented Mar 23, 2017 at 5:14
  • 1
    note you won't need the final cd ../.. in your version; changing directory in a subshell (within the parentheses ( ... )) won't change the working directory of the external shell. (at least that's how it works in bash.) Commented Mar 23, 2017 at 5:17
  • I dont think this will work unless you first issue IFS=$'\n' or similar (because of the space delimiter) Commented Mar 23, 2017 at 7:59
  • @quixotic - yup. I was pretty tired when I wrote that; I'm glad to see someone was able to improve on that. I really don't feel like getting reputation benefit/credit from your excellence, though. I'd rather see you post an answer and get well-deserved up-votes. Commented Mar 24, 2017 at 0:31
  • @davidgo it actually does work without IFS tweaking. for x in 'foo a' 'bar b' ... wouldn't. i assume the globbing provides the magic. @TOOGAM my answer got bogged down in explaining IFS and drowned. hard pass. Commented Mar 24, 2017 at 0:39
0

You're started correctly. However you can extend it a little in conjunction with the predicate -type to get just files. Using xargs and the bountiful powers of bash you have

find . -maxdepth 3 -mindepth 3 -type f |xargs -n1 bash -c 'cd $(dirname 0ドル) ; mv 0ドル ..'

0ドル is the positional argument passed to bash by xargs. To watch it as it happens you can use the -t option to xargs as -tn1

Note: I've limited the depth of search by using -mindepth $D and -maxdepth $D, feel free to change as per your requirements.

Note 2: Kamil's answer (using -execdir is actually a much better solution).

answered Mar 23, 2017 at 5:31

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.