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 {}
-
echo $( find . -name '.user.log' | xargs -I{} dirname {} )TOOGAM– TOOGAM2017年03月24日 01:52:46 +00:00Commented Mar 24, 2017 at 1:52
3 Answers 3
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.
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.)
-
1shorter:
for x in * ; do mv "$x"/*/* "$x"/ ; donequixotic– quixotic2017年03月23日 05:14:36 +00:00Commented Mar 23, 2017 at 5:14 -
1note 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 inbash.)quixotic– quixotic2017年03月23日 05:17:58 +00:00Commented 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)davidgo– davidgo2017年03月23日 07:59:32 +00:00Commented 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.TOOGAM– TOOGAM2017年03月24日 00:31:26 +00:00Commented Mar 24, 2017 at 0:31
-
@davidgo it actually does work without
IFStweaking.for x in 'foo a' 'bar b' ...wouldn't. i assume the globbing provides the magic. @TOOGAM my answer got bogged down in explainingIFSand drowned. hard pass.quixotic– quixotic2017年03月24日 00:39:18 +00:00Commented Mar 24, 2017 at 0:39
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).