Shell Script for Delete all files in directory and print count of deleted files - linux

I want to delete all files in directory and print count of deleted files using shell script.
this is my shell script to Delete All files
#!/bin/sh
rm -rf /Directory/SubDirectory/*
I tried this
rm -rf /Directory/SubDirectory/* | wc -l
Shell Script deleting all files but showing count as 0
My expected output as 100 files deleted.

The problem is that, by default, rm does not output anything, so there's nothing for wc to count.
You could use the -v option for rm (check your man page)
rm -vrf pattern | wc -l
# or
rm -vrf pattern | echo "$(wc -l) files deleted"
Another technique is to use find
find * -depth -print -delete | wc -l
Using the -depth directive so that a directory's files are removed before the directory itself. Demo:
$ tree
.
├── a
├── b
├── c
├── d
│   ├── g
│   ├── h
│   ├── i
│   └── k
│   ├── l
│   └── m
├── e
│   └── j
└── f
4 directories, 9 files
$ find * -depth -print -delete | wc -l
13
$ tree
.
0 directories, 0 files

flag -v, or --verbose used to explain what is being done.
The output will be like this:
removed 'tmp/1
removed 'tmp/2'
removed 'tmp/3'
removed directory 'tmp/'
By passing output through | wc -l you will count all of its records.
Nuance is it will count both removed files and directories. So, if you want only files to be counted you should use
rm -rfv rootDir | grep -v directory | wc -l

rm -rfv rootDir/directory/* | wc -l

Related

Change permission of a directory and subdirectories with xargs and chmod commands in linux

i have a list of directories in the current directory named with there permission codes (exemple : 552, 700, 777). I want to get the code permission from the name of directory and apply it to the directory and all the files it contains.
I tried with the xargs command :
find . -name "[0-9][0-9][0-9]" -type d | xargs chmod -R [0-9][0-9][0-9]
the problem with this command it takes the first directory and its change the permission code of all directories.
├── 555
│   └── logs
│   ├── 01.log
│   ├── 02.log
│   ├── 03.log
│   ├── 04.log
│   ├── 05.log
│   ├── 06.log
│   └── 07.log
├── 700
│   └── data
│   └── data1.data
what I want : I have the 555 directory so I want to change all sub files and directory with permission code 555 and for the second directory I want to change all the subfiles and directory with the permission code 700
what my command do: it change all other files and subdirectories with the permission code of the first file 500
Try
find . -name "[0-9][0-9][0-9]" -type d | sed 's#\./\(.*\)#\1#' | xargs -I{} chmod -R {} {}
the find is the same as yours.
the sed is added to remove the ./ from the directory name. Find returns ./700, ./555, ...
xargs with -I uses {} to reuse what it received into the command. So it says "chmod -R DIRNAME DIRNAME". So chmod -R 700 700 and so on.
In your attempt, xargs chmod -R [0-9][0-9][0-9], there is nothing to link the [0-9] in the find to the [0-9] in xargs.
Without xargs
find . -type d -regextype sed -regex ".*/[0-9]\{3\}$"| awk -F"/" '{print "chmod -R " $NF,$0}'|sh
find:
find . -type d -name '[0-7][0-7][0-7]' \
-exec sh -c 'for i do chmod -R "${i##*/}" "$i"; done' _ {} +
or a bash loop:
shopt -s globstar
for i in **/[0-7][0-7][0-7]/; do
i=${i%/}
chmod -R "${i##*/}" "$i"; done
done

Give out parent folder name if not containing a certain file

I am looking for a terminal linux command to give out the folder parent name that does not contain a certain file:
By now I use the following command:
find . -type d -exec test -e '{}'/recon-all.done \; -print| wc -l
Which gives me the amount of folders which contain then file.
The file recon-all.done would be in /subject/../../recon-all.done and I would need every single "subject" name which does not contain the recon-all.done file.
Loop through the directories, test for the existence of the file, and print the directory if the test fails.
for subject in */; do
if ! [ -e "${subject}scripts/recon-all.done" ]
then echo "$subject"
fi
done
Your command;
find . -type d -exec test -e '{}'/recon-all.done \; -print| wc -l
Almost does the job, we'll just need to
Remove | wc -l to show the directory path witch does not contain the recon-all file
Now, we can negate the -exec test by adding a ! like so:
find . -type d \! -exec test -e '{}'/recon-all.done \; -print
This way find will show each folder name if it does not contain the recon-all file
Note; Based on your comment on Barmar's answer, I've added a -maxdepth 1 to prevent deeper directorys from being checked.
Small example from my local machine:
$ /tmp/test$ tree
.
├── a
│   └── test.xt
├── b
├── c
│   └── test.xt
└── x
├── a
│   └── test.xt
└── b
6 directories, 3 files
$ /tmp/test$ find . -maxdepth 1 -type d \! -exec test -e '{}/test.xt' \; -print
.
./b
./x
$ /tmp/test$

How to copy folders and subfolders which have selected files

I have a directory oridir with structure as follows:
.
├── DIRA
│   ├── DIRA1
│   │   └── file2.txt
│   └── DIRA2
│   ├── file1.xls
│   └── file1.txt
└── DIRB
├── DIRB1
│   └── file1.txt
└── DIRB2
└── file2.xls
I have to copy files which have extension .xls while maintaining the directory structure. So I need to have following directory and files in a newdir folder:
.
├── DIRA
│   └── DIRA2
│   └── file1.xls
└── DIRB
└── DIRB2
└── file2.xls
I tried following command but it copies all files and folders:
cp -r oridir newdir
Finding required files can be done as follows:
$ find oridir | grep xls$
oridir/DIRB/DIRB2/file2.xls
oridir/DIRA/DIRA2/file1.xls
Also as follows:
$ find oridir -type f -iname *.xls
./oridir/DIRB/DIRB2/file2.xls
./oridir/DIRA/DIRA2/file1.xls
But how to create these folders and copy files. How can I achieve this selected creation of directories and copying files with `bash' in Linux?
Edit: There are space also in some file and directory names.
cp's --parents flag makes use full source file name under DIRECTORY
For example, if recursive glob ** is enabled (shopt -s globstar):
cp --parents origin/**/*.xls target
If recursive glob is not enabled, you have to add a wildcard for each level on directory hierarchy:
cp --parents origin/*/*/*.xls target
If a destination dir is "dest".
foo.sh
#!/bin/bash
dest=./dest
find . -type f -name "*.xls" | while read f
do
d=$(dirname "${f}")
d="${dest}/${d}"
mkdir -p "${d}"
cp "${f}" "${d}"
done
Make dirs and files.
$ mkdir -p DIRA/DIRA1
$ mkdir -p DIRA/DIRA2
$ mkdir -p DIRB/DIRB1
$ mkdir -p DIRB/DIRB2
$ touch DIRA/DIRA1/file2.txt
$ touch DIRA/DIRA2/file1.xls
$ touch DIRA/DIRA2/file1.txt
$ touch DIRB/DIRB1/file1.txt
$ touch DIRB/DIRB1/file2.xls
A result is
$ find dest
dest
dest/DIRB
dest/DIRB/DIRB1
dest/DIRB/DIRB1/file2.xls
dest/DIRA
dest/DIRA/DIRA2
dest/DIRA/DIRA2/file1.xls
See Yuji's excellent answer first, but I think tar is also a good option here:
cd oridir; find . -name "*.xls" | xargs tar c | (cd ../newdir; tar x)
You may need to adjust oridir and/or ../newdir depending on the precise paths of your directories.
Possible improvement: Here is a version that may be better in that it will handle files (and paths) with spaces (or other strange characters) in their names, and that uses tar's own options instead of xargs and cd:
cd oridir; find . -print0 -name "*.xls" | tar -c --null -T- | tar -C ../newdir -x
Explanation:
The -print0 and the --null cause the respective commands to separate filenames by the null (ASCII 0) character only.
-T- causes tar to read filenames from standard input.
-C causes tar to cd before extracting.

How to run a command on file in directory recursively creating a new file in each directory being visited (Bash)?

I have a directory with a few sub-directories.
.
├── alembic
│   └── results.csv
├── bigdata
│   └── results.csv
├── calchipan
│   └── results.csv
I'd like to create a copy of each results.csv file in the same directory named results_cleaned.csv where certain lines will be removed. Each sub-directory is known to contain only a single file, results.csv.
Running this on a single directory works:
find . -name 'results.csv' | xargs grep -v "Pattern" > results_cleaned.csv
However, running the same command on a root, produces just a single results_cleaned.csv file. I understand that I have to specify that I want to create a file in each sub directory individually, how do I do this?
You can't use xarg since all values are feed to single grep.
It would be better to iterate over each line of find (file names):
find . -name 'results.csv' | while read -r f
do
grep -v "Pattern" "$f" > "$(dirname "$f")/results_cleaned.csv"
done

Recursively scan directories in bash

I need to write a bash script that scans directories in current directory and generate md5 checksum values for each file in directory tree. It also should keep relative path to file and print checksums in a file.
For example if directory tree looks like this:
.
├── d
│   ├── file1.c
│   └── file2.c
├── e
│   └── file3.c
└── f
└── file4.cpp
The output should be something like this:
d8e8fca2dc0f896fd7cb4cb0031ba249 d/file1.c
d8e8fca2dc0f896fd7cb4cb0031ba249 d/file2.c
d8e8fca2dc0f896fd7cb4cb0031ba249 e/file3.c
d8e8fca2dc0f896fd7cb4cb0031ba249 f/file4.cpp
But I can't find a way to keep path to file when cd to them...
find . -type f -exec md5sum {} \;
or...
find . -type f | xargs -n 1 -d "\n" md5sum

Resources