Delete all files and folders recursively but excluding one folder - linux

I have a folder structure like this:
my-root-folder
├── .git
├── README.md
├── index.css
├── index.js
├── index.html
├── assets
│ ├── image
│ │ ├── logo.jpg
│ │ ├── header.jpg
i want delete all files and folder into my-root-folder but not the .git folder (./my-root-folder/.git) and his child.
i have tried with this command, but always delete all:
shopt -s extglob && rm -rf ./* !(".git")
Side note i'm in a docker image based on alpine.

You can try with find:
find my-root-folder -mindepth 1 -not -path "*/.git*" -delete
Roughly translated, this means: find inside my-root-folder everything at least one level deep (so, exclude the folder itself) that does not match the predicate path contains "/.git" and delete it.
Note that the argument ".git" is actually a regular expression, so be careful when adapting to other situations. find is a very powerful and useful tool, so be sure to check out its documentation!

This find command delete nested .git as well :
find . -mindepth 1 -path ./.git -prune -o -exec echo rm -rf {} \;
-path ./.git -prune -o excludes only top level .git
One drawback is you may see messages because find tries to access directories it has already deleted.
Remove echo once you are happy.

Related

Find files missing in one directory that are in a second - needs to ignore file extension

I need to find files missing in one directory that are in a second, but I need to ignore file extensions. I need to do this based on file name only, not fill contents. If my file names were identical (including extensions), I could use diff something like:
diff dirA dirB
, however files in directory A have a different extension from those in directory B. I need a way to use something like diff but to ignore the extension differences between the two directories.
Another important point is that each directory may contain hundreds of thousands of files, so I have a need for a relatively efficient process.
Grateful for any ideas.
I hope it helps
I created sample files, look like this
sample
/
├── a
│   ├── 1
│   └── 3
└── b
│   ├── 1
│   ├── 2
│   └── 3.txt
$comm -13 <(find a/ -type f -exec bash -c 'basename "${0%.*}"' {} \; | sort) <(find b/ -type f -exec bash -c 'basename "${0%.*}"' {} \; | sort)
output:
2

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

Find command inconsistent output , wild card not working correctly

I am using find command to create a list of files that I want to use for distribution bundle. but find is not able to get the list of all files
Below is my directory structure
.
├── 1.cpp
├── test
│   └── 1.cpp
└── test1
├── 1.cpp
└── test11
├── 1.h
└── 2.cpp
below is the command and its output ( note: it does not bring the ./test1/test11/2.cpp)
$ find . -name *.cpp
./test/1.cpp
./1.cpp
./test1/1.cpp
however when i am using the specific name it is able to locate the file
$ find . -name 2.cpp
./test1/test11/2.cpp
it's because *.cpp is expanded to 1.cpp because there is a match in current directory use quotes "*.cpp" or escape star \*.cpp to avoid expansion and pass star literaly as argument for find.
Add double quote in your search string find . -name "*.cpp"

Copy directory structure ignoring some files

I have a directory structure
./
└── file1
├── config.xml
├── config.yml
└── file2
├── config.xml
├── config.yml
└── file3
├── config.xml
└── config.yml
What i want is to copy same directory structure and everything but
ignoring config.yml files in the new location Any Linux Command or
script Thanks in advance
As i understood you just want to replicate the folder structure,
You could do something like:
find . -type d >dirs.txt
to create the list of directories, then
xargs mkdir -p <dirs.txt
to create the directories on the destination.
Take a look at this https://stackoverflow.com/a/4073992/6916391
You can do it in two steps by copying the whole structure and then removing the config.yml files, this is:
cp -R old_structure_parent_dir new_structure_parent_dir
find new_structure_parent_dir -name config.yml -exec rm -rf {} \;

Resources