Archive old directories and delete them - linux

How can we archive old directories and delete them after? If we suppose an old directory is one who has modified last time at least three days ago, I am able to get my directories list with
find . -mindepth 2 -type d -mtime 3
which return a list like
./dir1/1394547493
./dir2/1394525075
./dir2/1394531732
./dir3/1394546562
Now we need for any directory from this list to create a .ZIP archive in coresponding dirX containing ONLY the files from it (there are no more other directories in those directories), and delete the subdirectory right after. In the end our structure should look like this
./dir1/1394547493.zip
./dir2/1394525075.zip
./dir2/1394531732.zip
./dir3/1394546562.zip
Resulting archives must not contains any paths.

Try this one-liner:
for dir in $(find . -mindepth 2 -type d -mtime 3); do cd "$dir" && zip ../$(basename "$dir") * && cd - && rm -rf "$dir" || cd -; done
This one-liner enters each directory, zips its contents without parent directories and removes the directory on success, but leaving the directory in place in case of failure.
Good luck :)
Edit: Your directory names are required to not include spaces or tabs

Related

Unix shell loop to check if a directory exists inside multiple directories

I have folder structure like this:
/home/
/folder1/
/backup/
/folder2/
/backup/
/folder3/
/folder4/
/backup/
/folder5/
(As you can see, no all directories "folder" have a directory "backup")
I need to check if the directory "backup" exists in the "folder"s and delete it.
I am using this command:
for d in /home/* ;
do [ -d "$d/backup" ]
&& echo "/backup exists in $d"
&& rm -rf "$d/backup"
&& echo "/backup deleted in $d" ;
done
But it is not working. Please help.
find . -type d -name "backup" -delete -print
Obviously, all content under backup directories will be lost.
This will recurse down into your directories. If you need to limit it to only the first level, you can do:
find . -maxdepth 1 -type d -name "backup" -delete -print
Both commands will print the deleted directories. No output == no directory found, nothing done.
Lastly, you want to avoid looping on files or directory names like you attempted, since you might have files or directories with spaces in their names. A complete discussion and solutions are available here: https://mywiki.wooledge.org/BashFAQ/001

Recursively unzip all subdirectories while retaining file structure

I'm new to bash scripting, and i'm finding it hard to solve this one.
I have a parent folder containing a mixture of sub directories and zipped sub directories.
Within those sub directories are also more nested zip files.
Not only are there .zip files, but also .rar and .7z files which also contain nested zips/rars/7zs.
I want to unzip, unrar and un7z all my nested sub directories recursively until the parent folder no longer contains any .rar, .zip, .7zip files. (these eventually need to be removed when they have been extracted). There could be thousands of sub directories all at different nesting depths. You could have zipped folders or zipped files.
However I want to retain my folder structure, so the unzipped folders must stay in the same place where it has been unzipped
I have tried this script that works for unzipping, but it does not retain the file structure.
#!/bin/bash
while [ "`find . -type f -name '*.zip' | wc -l`" -gt 0 ]
do
find . -type f -name "*.zip" -exec unzip -- '{}' \; -exec rm -- '{}' \;
done
I want for example:
folder 'a' contain zipped folder 'b.zip' which contains a zipped text file pear.zip (which is pear.txt that has been zipped to pear.zip a/b.zip(/pear.zip))
I would like folder 'a' to contain 'b' to contain pear.txt 'a/b/pear.txt'
The script above brings 'b' (b is empty) and pear both into folder 'a' where the script is executed which is not what I want. eg 'a/b' and 'a/pear.txt'
You could try this:
#!/bin/bash
while :; do
mapfile -td '' archives \
< <(find . -type f -name '*.zip' -o -name '*.7z' -print0)
[[ ${#archives[#]} -eq 0 ]] && break
for i in "${archives[#]}"; do
case $i in
*.zip) unzip -d "$(dirname "$i")" -- "$i";;
*.7z) 7z x "-o$(dirname "$i")" -- "$i";;
esac
done
rm -rf "${archives[#]}" || break
done
Every archive is listed by find. That list is extracted in the correct location and the archives removed. This repeats, until zero archives are found.
You can add an equivalent unrar command (I'm not familiar with it).
Add -o -name '*.rar' to find, and another case to case. If there's no option to specify a target directory with unrar, you could use cd "$(dirname "$i")" && unrar "$i".
There are some issues with this script. In particular, if extraction fails, the archive is still removed. Otherwise it would cause an infinite loop. You can use unzip ... || exit 1 to exit if extraction fails, and deal with that manually.
It's possible to both avoid removal and also an infinite loop, by counting files which aren't removed, but hopefully not necessary.
I couldn't test this properly. YMMV.

copying files from etc ending with digit to test1 directory

I'm new to linux and as an exercice I need to copy the "etc" files that end with a digit from home directory to the test1 directory
(with one command).
I tried this but it dosn't work
find /etc -type f -iname "*[3-9]" -exec cp {} ../test1/ \;
this should work for your home directory files ending with digit
mv `ls . |grep -Eo "^.*[0-9]$"` your-directory
lets says in the current directory you have some files like ofjweifhwef9 or kfhiofeh8 ( files ending with digit)
so ls will list them.
this grep expression "^.*[0-9]$"` will find only files ending with digit. ( because in your home directory system wont allow to have a file like this "/etc/somefile123")
and then mv will move those files to your-directory
note :- if grep cannot find the files ending with number you will see an error ofcourse because mv needs 2 operands but since it wasn't there so error.
mv: missing destination file operand after './your-directory'
It is probably because /etc is a link in the system that you're using, and find doesn't seem to consider it a path until you add an extra / at the end. Try this instead:
find /etc/ -type f -iname "*[3-9]" -exec cp {} ../test1/ \;
Notice the /etc/ instead of /etc. I get the same behavior on my Mac where /etc is a link to another directory.
Of course, also make sure that you have files which names end on a digit under the /etc/ directory tree. I have none in my mac. You should get some files when you run:
find /etc/ -type f -iname "*[3-9]"
If you don't, you don't have any files to copy. You may also try: find /etc/ to see all files under the directory tree.
Finally, you may want to add the option: -depth 1 if you only want to copy the files in the /etc/ directory, as opposed to all the files that match in the directory tree under /etc/.

Wrtie a script to Delete files if it exists in different folder in Linux

I'm trying write a script in linux. Where I have some csv files in Two different folders(A and B) and then after some processing copy of rejected files are moving to Bad Folder.
SO I want bad files to be deleted from Table A and B which have copied to Bad Folder.
Can you help me to write this script for linux?
Best
lets say name of Bad Folder is 'badFolder' and considering 'A', 'B' and 'badFolder' are in same directory
Steps to delete files from folder A and B:
step 1: change current directory to your 'badFolder'
cd badFolder
step 2: delete identical files
find . -type f -exec rm -f ../A/{} \;
find . -type f -exec rm -f ../B/{} \;
The argument -type f tells to look for files, not directories.
The -exec ... \; argument tells that, once it finds a file in 'badFolder', it should run the command rm -f on its counterpart in the A subdirectory.
Because rm is given with the -f option, it will silently ignore files that don't exist.
Also, it will not prompt before deleting files. This is very handy when deleting a large number of files. However, be sure that you really want to delete the files before running this script.
#!/bin/bash
#Set the working folder in which you want to delete the file
Working_folder=/<Folder>/<path>
cd $Working_folder
#command to delete all files present in folders
rm <filenames seperated by space>
echo "files are deleted"
#if you want to delete all files you can use wild card character
# e.g. command rm *.*
# if you want to delete a particular file say for deleting .csv file you can use command rm *.csv command
Set variables containing the paths of your A, B and BAD directories.
Then you can do something along the lines of
for file in ls ${PATH_TO_BAD}
do
rm ${PATH_TO_A}/$file
rm ${PATH_TO_B}/$file
done
This is iterating over the BAD directory and any file it finds, it deletes from the A and B directories.

Copy modified files with directory structure in linux

How can I copy a list of files modified today with the directory structure into a new directory. As shown in the following command I want to copy all the files modified today from /dev1/Java/src into /dev2/java/src. The src folder has many sub directories.
find /dev1/Java/src -newermt 2014-06-10 > 1.txt
for f in $(cat 1.txt) ; do cp $f /dev2/Java/src; done
You can take advantage of find and cpio utility.
cd /dev1/Java/src; find . -mindepth 1 -mtime -1 | cpio -pdmuv /dev2/Java/src
The above command goes to the source directory and finds the list of new files relative to the source directory.
The output is read by cpio and copies the files into the target directory in the same structure as the source, hence the need for relative pathnames.
Extracts the files modified within a day and copies them to the desired path.
find . -type f -mtime -1 -exec cp {} /path \;

Resources