How can I find directories to zip with specific path structure - bash

I am in bash.
I have the following directories.
/mydir/moredirs/archivethis1
/mydir/moredirs/archivethis2
/mydir/moredirs/subdirA
/mydir/moredirs/subdirB
I am able to cd to /mydir/moredirs
and then
zip ~/archivethis1.zip archivethis1/*.*
I want to use find as follows:
cd /mydir/moredirs
find * -type d -name "archive*" -exec zip ~/{}.zip {}/*.* \;
I receive following error:
zip warning: name not matched: zip error: Nothing to do!
Can I use find to find all directories named archive and then zip them with the same path structure as running the zip command as illustrated for a single directory. Note, this is why I am using find * vs find . and why I cd into parent directory to make that the CWD.
I prefer using /*.* vs -r flag as this does not include empty dir in zip structure.

I have to correct my suggestion
find: warning: you have specified the global option -maxdepth after
the argument -type, but global options are not positional, i.e.,
-maxdepth affects tests specified before it as well as those specified after it. Please specify global options before other arguments.
find . -maxdepth 1 -type d -name "archive*" -exec zip -r ~/"{}".zip "{}" \;

Related

Find and rename multiple files using a bash script in Linux

As an example, in a directory /home/hel/files/ are thousends of files and hundreds of directories.
An application saves there its output files with special characters in the file names.
I want to replace these special characters with underscores in all file names. e.g. -:"<>#
I wrote a bash script which simply repeats a command to rename the files using Linux/Unix 'rename'.
Example: file name: rename.sh
#!/bin/bash
rename "s/\'/_/g" *
rename 's/[-:"<>#\,&\s\(\)\[\]?!–~%„“;│\´\’\+#]/_/g' *
rename 'y/A-Z/a-z/' *
rename 's/\.(?=[^.]*\.)/_/g' *
rename 's/[_]{2,}/_/g' *
I execute the following find command:
find /home/hel/files/ -maxdepth 1 -type f -execdir /home/hel/scripts/rename.sh {} \+
Now the issue:
This works fine, except the fact, that it renames subdirectories too, if they have the searched characters in their name.
The find command searches just for files and not for directories.
I tried some other find variations like:
find /home/hel/files/ -maxdepth 1 -type f -execdir sh /home/hel/scripts/rename.sh {} \+
find /home/hel/files/ -maxdepth 1 -type f -execdir sh /home/hel/scripts/rename.sh {} +
find /home/hel/files/ -maxdepth 1 -type f -execdir sh /home/hel/scripts/rename.sh {} \;
They are all working, but with the same result.
What is not working:
find /home/hel/files/ -maxdepth 1 -type f -exec sh /home/hel/scripts/rename.sh {} \+
This one is dangerous, because it renames the directories and files in the current directory, where you call the find command too.
Maybe one has an idea, why this happens or has a better solution.
The script rename.sh did not use its command line arguments at all, but instead searched files and directories (!) on its own using the glob *.
Change your script to the following.
#!/bin/bash
rename -d s/\''/_/g;
s/[-:"<>#\,&\s\(\)\[\]?!–~%„“;│\´\’\+#]/_/g;
y/A-Z/a-z/;
s/\.(?=[^.]*\.)/_/g;
s/[_]{2,}/_/g' "$#"
Then use find ... -maxdepth 1 -type f -exec sh .../rename.sh {} +.
Changes Made
Use "$#" instead of * to process the files given as arguments rather than everything in the current directory.
Execute rename only once as a 2nd rename wouldn't find the files specified with "$#" after they were renamed by the 1st rename.
Use the -d option such that only the basenames are modified. find always puts a path in front of the files, at the very least ./. Without this option rename would change ./filename to mangledPath/newFilename and therefore move the file to another directory.
Note that man rename is a bit misleading
--path, --fullpath
Rename full path: including any directory component. DEFAULT
-d, --filename, --nopath, --nofullpath
Do not rename directory: only rename filename component of path.
For a given path rename -d 's...' some/path/basename just processes the basename and ignores the leading components some/path/. If basename is a directory it will still be renamed despite the -d option.

Bash script for removing specific file from certain subdirectories

On a unix server, I'm trying to figure out how to remove a file, say "example.xls", from any subdirectories that start with v0 ("v0*").
I have tried something like:
find . -name "v0*" -type d -exec find . -name "example.xls" -type f
-exec rm {} \;
But i get errors. I have a solution but it works too well, i.e. it will delete the file in any subdirectory, regardless of it's name:
find . -type f -name "example.xls" -exec rm -f {} \;
Any ideas?
You will probably have to do it in two steps -- i.e. first find the directories, and then the files -- you can use xargs to make it in a single line, like
find . -name "v0*" -type d | \
xargs -l -I[] \
find [] -name "example.xls" -type f -exec rm {} \;
what it does, is first generating a list of viable directory name, and let xargs call the second find with the names locating the file name within that directory
Try:
find -path '*/v0*/example.xls' -delete
This matches only files named example.xls which, somewhere in its path, has a parent directory name that starts with v0.
Note that since find offers -delete as an action, it is not necessary to invoke the external executable rm.
Example
Consider this directory structure:
$ find .
.
./a
./a/example.xls
./a/v0
./a/v0/b
./a/v0/b/example.xls
./a/v0/example.xls
We can identify files example.xls who have one of their parent directories named v0*:
$ find -path '*/v0*/example.xls'
./a/v0/b/example.xls
./a/v0/example.xls
To delete those files:
find -path '*/v0*/example.xls' -delete
Alternative: find only those files directly under directory v0*
find -regex '.*/v0[^/]*/example.xls'
Using the above directory structure, this approach returns one file:
$ find -regex '.*/v0[^/]*/example.xls'
./a/v0/example.xls
To delete such files:
find -regex '.*/v0[^/]*/example.xls' -delete
Compatibility
Although my tests were performed with GNU find, both -regex and -path are required by POSIX and also supported by OSX.

How to use (shell) find to recursively find files of specific type then cp only the newest one for each folder

I'm trying to write a script that goes into a folder that has a bunch of zip files that were unzipped, then use the find command to search each subdirectory recursively, look for files of the .MCA type, and finally copy only the newest one to another directory. So far I can't figure out how to grab only the newest file. Would -newer work? How would I do this for every file?
find . -mindepth 2 -name "*.MCA" -exec cp {} tempMCA \;
If you can use rsync instead of cp then you can run:
find . -mindepth 2 -name '*.MCA' -exec rsync --update {} tmpMCA \;
The --update option tells rsync to only copy the files if the source is newer than the destination.

How to find all non-binary text files (with extended attributes) in a directory on OSX bash?

The following command cann't work when the file name contains extended attributes.
cd ~/Library/Containers
find . -type f -name "*.xml"
It returned nothing. But
less com.apple.TextEdit/Data/Music/iTunes/iTunes\ Music\ Library.xmlary.xml
The xml file is there.
In order to follow the symbolic links in the directory hierarchy, you need to use the -L option to find:
find -L . -type f -name "*.xml"

get a list of files and directories with full path in unix

I am trying to get full path of both the files and directories from a directory. I tried using find but unable to get result.
when I used find /home/demo -type f it only lists files and find /home/demo -type d only lists directories.
Is there a way to get both using Find?
You can specify the absolute path of a directory. As an example for the current directory:
find "`pwd`"
pwd shows full path of current directory. ` ` summons a subshell in which output can be used as an argument to the command.
A literal example can be:
find /home/user
Update: You can use -o to explicitly target both files and directories. Doing find without an option may include other types besides the two.
find /home/user \( -type f -o -type d \)
Note: -or is synonymous but may not work in other versions of find since it's not POSIX compliant.

Resources