Create Symlink from recursive search in a certain folder - bash

I want to create Symlinks for a recursive find search.
This should also work for folders containing spaces.
The Symlinks should get created in a certain folder.
I tried to use this script:
IFS=$'\n'
for t in $(find . -type d -name "*search*" | sed 's|.*/||'); do
ln -s "$t" "./symlink-folder/$t"
done
the problem is that the full path of the files does not get passed to ln, so the links created are all broken.

ok, seems like I made it running with:
cd ./symlink-folder/
find ../ -type d -name "*search*" -exec ln -s {} . ';'
it does work with spaces

Related

Delete nested subdirectories by name on Mac?

How can I delete all subdirectories of a certain name via the command line on mac?
Eg if I have
/parent/foo
/parent/child/foo
/parent/child/child2/foo
How can I run a command from /parent that will delete any folder called foo and all of it's contense?
Ive tried this command but no luck:
find . -type d -name foo -delete
Using find you can do:
find . -d -type d -name a -exec rm -r {} \;
As you have discovered -delete does not appear to delete non-empty directories (so its equivalent to rmdir not rm -r), though this may not be documented.
The -exec executes a command, {} is replaced by the matching pathname, and \; marks the end of the command. So this does a recursive removal of every matching path.
The -d sets depth first traversal which means directories are processed after their contents. If you omit this find will first remove the directory and then try to recurse into it – this results in error messages but still works.
There is a shorter way using zsh:
rm -r **/a
The pattern ** does a search an matches a at any depth.
If zsh is not your default shell you can use its -c argument to run a command from another shell:
zsh -c 'rm -r **/a'
HTH
The name of the directory has to be in quotes.
Do the following:
find . -type d -name "foo" -delete

How to delete all files or Sub-folders (both) in a folder except 2 folders with shell script

I would like to know how to deleted all the contents of a folder (it contains other folders and some files) except for 2 folders and its contents
The below command keeps the folder conf and removes all the other folders
find . ! -name 'conf' -type d -exec rm -rf {} +
I have tried to pipe it like below
find . -maxdepth 1 -type d ! -name 'conf' |find . -maxdepth 1 -type d ! -name 'foldername2'
but didnt work.
is it possible to do with a single command
You haven't specified which shell you're using, but if you're using bash then extended globs can help:
printf '%s\n' !(#(conf|foldername2)/)
If you're happy with the list of files and directories produced by that, then pass the same glob to rm -rf:
rm -rf !(#(conf|foldername2)/)
Inside a script, you may need to enable extglob using shopt -s extglob. Later, you can change -s to -u to unset the option.
If you're using a different shell, then you can add some more options to your find command:
find -maxdepth 1 ! -name 'conf' -a ! -name 'foldername2' -exec rm -rf {} +
Try it without the -exec part first to print the matches rather than deleting everything.
It may my little program utility can help you. I hope so.
First of all you should find the path of your files .sh
then you should find the main folder that contains those files .sh
then remove anything except those folders
I wrote drr for such a purpose that it can do such a task so easy
drr, stands for: remove or rename files based on regular expression in D language. So you must compile it before using.
See the screenshot:
Please be careful since this is not an appropriate tool for beginner.

Unix: Batch move files from multiple subdirectories up 1 level

How can I move files from several subdirectories up 1 level in one terminal command?
File Structure:
path/to/files/A/remove/image.png
path/to/files/B/remove/image.png
path/to/files/C/remove/image.png
path/to/files/D/remove/image.png
path/to/files/E/remove/image.png
Desired Structure:
path/to/files/A/image.png
path/to/files/B/image.png
path/to/files/C/image.png
path/to/files/D/image.png
path/to/files/E/image.png
There are A LOT of directories and each "letter" directory above includes several images. Also, would like to delete the directory the files were moved from.
I had the same requirement (on a mac) but in my case the subdirectory did not have the same name as in the original question making it a bit more complicated. This is what worked for me:
from the "path/to" folder I ran
find . -mindepth 3 -maxdepth 3 -type f | awk -v sq="'" -F "/" '{print "mv -i " sq $0 sq " " sq "./" $2 sq}' > moveup.sh
and then
sh moveup.sh
There are many ways to do it.
This moves all files to their grand-parent directory:
$ find path/to/files -type f -exec mv {} $(dirname $(dirname {})) \;
You add a -name \*.type or whatever, instead of the -type f option, in order to be more specific.
This removes empty directories:
$ find . -type d -empty -exec rmdir {} \;
(although it generates benign errors, which I guess is because the directory structure has been altered while find is still working).
I found the solution to my question...
Using the example directories in my original question, I used this command:
for a in $(find path/to/files -maxdepth 1 -type d); do mv $a/remove/* $a/; rmdir $a/remove; done
"remove" is the name of the subdirectory I wanted to move the files out of within each directory.
The answer was actually found here:
https://serverfault.com/questions/405146/how-to-mass-move-files-one-directory-up

How to create in all subfolders of a given directory subfolder with given name

I have a directory structure like this in my CentOS:
dir1
dir2
dir3
...
Now, I would like to create in each dirN folder a sub-folder named converted. I tried with:
> find . -maxdepth 1 -type d -execdir mkdir converted {} +
But without success. Could anybody help?
TCLSH VERSION:
find . -maxdepth 1 -type d -exec mkdir -p \{\}/converted \;
You have to escape the curly braces with "\".
BASH VERSION:
Fist login into BASH:
bash --login
then perform the command:
sudo find . -maxdepth 1 -type d -exec mkdir -p {}/converted \;
What worked out for me.
But it also creates the folder converted on top of those directories.
Also are you in the specific folder where you want to create those sub dirs?
If not please navigate first into the folder or change the find command params like so:
sudo find /PATH/TO/YOUR/DIR -maxdepth 1 -type d -exec mkdir -p {}/converted \;
IF you really want to stick to tclsh:
Optional:
This is just my opinion:
You should really use BASH or ZSH for your daily sysadmin/programming work.
If you want to change the $SHELL type in:
sudo chsh
Another way:
bash
for i in dir*; do [ -d "$i" ] || continue; mkdir "$i"/converted; done

Renaming Subdirectories and Files

I have a script using a for loop that would rename folders and files. The script would take the list of files and folders and rename them conditionally. I would invoke the file using the command:
find test/* -exec ./replace.sh {} \;
My replace.sh script would contain something similar to:
for i in $#
mv $OLDFILE $NEWFILE
done
$OLDFILE and $NEWFILE has been set previously and I don't believe any problems will arise from them.
My problem arises when I hit upon subdirectories. Originally, I would have folders like:
folder_1
-file1
-file2
When my script changes folder_1 into folderX1, the next argument, folder_1/file1 woudl be invalid as the changed path would be folderX1/file1. I figured I could create a stack with a list of folders that is being changed and pop them out later to rename the files but this seems hard on bash. Is there a better method that I am missing?
P.S I could run the program several times to go through all the subdirectories but this doesn't seem efficient.
You can add -depth to the find command. This will process the directory's files before the directory itself. See man find for details.
Your find usage is problematic. The first option is the start location for the search, so you don't want to use a glob there. If you want only the files in test/ and not any of its subdirectories, use the -depth option, as Olaf suggested.
You don't really need to use a separate script to handle this rename. It can be done within the find command line, if you don't mind a little mess.
To handle just the top-level of files, you could do this:
$ touch foo.txt bar.txt baz.ext
$ find test -depth 1 -type f -name \*.txt -exec bash -c 'f="{}"; mv -v "{}" "${f/.txt/.csv}"' \;
./foo.txt -> ./foo.csv
./bar.txt -> ./bar.csv
$
But your concern is valid -- find will build a list of matches, and if your -exec changes the list out from under find, some renames will fail.
I suspect your quickest solution is to do this in TWO stages (not several): one for files, followed by one for directories. (Or change the order, I don't think it should matter.)
$ mkdir foo_1; touch red_2 foo_1/blue_3
$ find . -type f -name \*_\* -exec bash -c 'f="{}"; mv -v "{}" "${f%_?}X${f##*_}"' \;
./foo_1/blue_3 -> ./foo_1/blueX3
./red_2 -> ./redX2
$ find . -type d -name \*_\* -exec bash -c 'f="{}"; mv -v "{}" "${f%_?}X${f##*_}"' \;
./foo_1 -> ./fooX1
Bash parameter expansion will get you a long way.
Another option, depending on your implementation of find, is the -d option:
-d Cause find to perform a depth-first traversal, i.e., directories
are visited in post-order and all entries in a directory will be
acted on before the directory itself. By default, find visits
directories in pre-order, i.e., before their contents. Note, the
default is not a breadth-first traversal.
So:
$ mkdir -p foo_1/bar_2; touch red_3 foo_1/blue_4 foo_1/bar_2/green_5
$ find . -d -name \*_\* -exec bash -c 'f="{}"; mv -v "{}" "${f%_?}X${f##*_}"' \;
./foo_1/bar_2/green_5 -> ./foo_1/bar_2/greenX5
./foo_1/bar_2 -> ./foo_1/barX2
./foo_1/blue_4 -> ./foo_1/blueX4
./foo_1 -> ./fooX1
./red_3 -> ./redX3
$

Resources