Remove directory structure, but keep directory contents - linux

I meant to run this code inside a specific directory within my home directory, but accidentally ran it in my home directory itself:
i=0; for f in *; do d=dir_$(printf %03d $((i/8+1))); mkdir -p $d; mv "$f" $d; let i++; done
Now all my files and directories have been grouped into separate directories. I need to remove this action, and restore my original organization. Is this possible?

Using shell expansion:
mv dir_*/* .
should move the content of all dir_ subdirectories back into the current one. For "hidden" files, if necessary, move dir_*/.*.

Related

How to move files from subdirectory to a directory using a for loop

How do I move a file 1 directory up using loop? Can someone maybe help me out?
I tried this:
for dir in */*/
do mv "$dir"/*
done
Like that:
for dir in */*/
do
echo mv "$dir"* "${dir%/*/}" # Drop the echo after tested it
done
Note that this will move all files and directories under $dir to the parent directory of the $dir. If you want to move a specific file, replace "$dir"* with "$dir"file where file is the filename of the specific file. Also be very careful where and how you use this code after echo removed (running in the wrong directory would be catastrophic)

Create directory based on date/time and copy files to it?

I'm attempting to create a script that will create a folder based on the current time and date. I then need the script to copy the files from a source folder to the newly created folder. I then need it to copy folders from a second source folder to the original source folder, overwriting everything that's in there.
Below is what I've tried, and it's failing in quite an epic fashion.
#!/bin/bash
d="/home/$(date +%d-%m-%y")"
mkdir "$d"
cp /home/test "$d"
cp /home/test2 /home/test
I'm aware that I don't have to define the variable, as the time between copies should be seconds and not lapse a day, but I wanted to make sure and honestly, I'm interested in learning to use variables in scripting.
There is one too many double quote here:
d="/home/$(date +%d-%m-%y")"
Actually no quoting is necessary here at all, write like this:
d=/home/$(date +%d-%m-%y)
In the rest of the script, if you want to copy directories, you will need to use cp -r instead of simply cp.
Finally, note that when you do cp -r dir1 dir2 when dir2 already exists, then dir1 will be copied inside dir2, rather than overwriting its content. That is, it will create dir2/dir1. If dir1 doesn't contain hidden files, then you can write like this to overwrite the content of dir2:
cp -r dir1/* dir2/

Linux Bash: Move multiple different files into same directory

As a rather novice Linux user, I can't seem to find how to do this.
I am trying to move unique files all in one directory into another directory.
Example:
$ ls
vehicle car.txt bicycle.txt airplane.html train.docx (more files)
I want car.txt, bicycle.txt, airplane.html, and train.docx inside vehicle.
Right now I do this by moving the files individually:
$ mv car.txt vehicle
$ mv bicycle.txt vehicle
...
How can I do this in one line?
You can do
mv car.txt bicycle.txt vehicle/
(Note that the / above is unnecessary, I include it merely to ensure that vehicle is a directory.)
You can test this as follows:
cd #Move to home directory
mkdir temp #Make a temporary directory
touch a b c d #Make test (empty) files ('touch' also updates the modification date of an existing file to the current time)
ls #Verify everything is there
mv a b c d temp/ #Move files into temp
ls #See? They are gone.
ls temp/ #Oh, there they are!
rm -rf temp/ #DESTROY (Be very, very careful with this command)
Shorthand command to move all .txt file
You can try using a wildcard. In the code below, * will match all the files which have any name ending with .txt or .docx, and move them to the vehicle folder.
mv *.txt *.docx vehicle/
If you want to move specific files to a directory
mv car.txt bicycle.txt vehicle/
Edit: As mentioned in a comment, If you are moving files by hand, I suggest using mv -i ... which will warn you in case the destination file already exists, giving you a choice of not overwriting it. Other 'file destroyer' commands like cp & rm too have a -i option
mv command in linux allow us to move more than one file into another directory. All you have to do is write the name of each file you want to move, seperated by a space.
Following command will help you:
mv car.txt bicycle.txt airplane.html train.docx vehicle
or
mv car.txt bicycle.txt airplane.html train.docx vehicle/
both of them will work.
You can move multiple files to a specific directory by using mv command.
In your scenario it can be done by,
mv car.txt bicycle.txt airplane.html train.docx vehicle/
The point you must note is that the last entry is the destination and rest everything except mv is source.
One another scenario is that the destination is not present in our directory,then we must opt for absolute path in place of vehicles/.
Note: Absolute path always starts from / ,which means we are traversing from root directory.
I have written a small bash script that will move multiple files(matched using pattern) present in multiple directories(matched using pattern) to a single location using mv and find command in bash
#!/bin/bash
for i in $(find /path/info/*/*.fna -type f) # find files and return their path
do
mv -iv $i -t ~/path/to/destination/directory # move files
done
$() is for command substitution(in other words it expand the expression inside it)
/*/ wild card for matching any directory, you can replace this with any wild card expression
*.fna is for finding any file with.fna extension
-type f is for getting the full path info of the located file
-i in mv is for prompt before overwrite( extra caution in case the wild card exp was wrong)
-v for verbose
-t for destination
NOTE: the above flags are not mandatory
Hope this helps

Bash script to delete a file in all sub directories.

I have a directory that is filled with subdirectories exceeding 450 GBs. Inside of these subdirectories is an instruction file in each subdirectory. I have a script that copies the instruction file in the directory I am currently in and puts it inside every subdirectory via:
#!/bin/bash
for d in */; do cp "INSTALLATION INSTRUCTIONS.rtf" "$d"; done
I need to remove all of these files in the subdirectories and replace them with new instructions. Can I simple write another script that does this:
#!/bin/bash
for d in */; do rm "INSTALLATION INSTRUCTIONS.rtf" "$d"; done
I am very hesitant and wanted to make sue as these files are vitally important and I don't want to accidentally remove anything and making a backup of 450+ GBs is very taxing.
find . -mindepth 2 -name "INSTALLATION INSTRUCTIONS.rtf" -exec rm -f '{}' +
Since this is "vitally important" data, I would first list all files that match the file name you want to delete/overwrite, without taking any action on it (other than listing):
find /folder/ -type f -name "INSTALLATION INSTRUCTIONS.rtf" -print > /tmp/holder
That would create a list of matches on /tmp/holder. Then you could analyze this list before taking any action (either visually or programatically) to make sure that the list does not include anything you don't want to delete (when dealing with big amounts of data, strange things can happen, so be proactive on protecting the data).
If you are happy with what the list shows, then you could delete the old instructions, or if possible, overwrite them with the new file. Here's an example to overwrite the old file with the new one:
while read -r line; do cp --no-preserve=all /folder/newfile "$line"; done < /tmp/holder
The cp --no-preserve=all command (available on GNU bash) would ensure that the new file has permissions that are "adequate" to the folder where they are located. You may change that to a simple cp if you don't want that to happen.

mv: cannot overwrite directory with non-directory

Is it possible to get around this problem?
I have a situation where I need to move some files to 1 directory below.
/a/b/c/d/e/f/g
problem is that the filename inside g/ directory is the same as the directory name
and I receive the following error:
mv: cannot overwrite directory `../297534' with non-directory
Example:
/home/user/data/doc/version/3766/297534 is a directory, inside there is a also a file named 297534
so I need to move this file to be inside /home/user/data/doc/version/3766
Command
This is what I am running: (in a for loop)
cd /home/user/data/doc/version/3766/297534
mv * ../
You can't force mv to overwrite a directory with a file with the same name. You'll need to remove that file before you use your mv command.
Add one more layer in your loop.
Replace mv * ../ with
for f in `ls`; do rm -rf ../$f; mv $f ..; done
This will ensure that any conflict will be deleted first, assuming that you don't care about the directory you're overwriting.
Note that this will blow up if you happen to have a file inside the current directory which matches the current directory's name. For example, if you're in /home/user/data/doc/version/3766/297534 and you're trying to move a directory called 297534 up. One workaround to this is to add a long suffix to every file, so there's little chance of a match
for f in `ls`; do mv $f ../${f}_abcdefg; done

Resources