How to force "ln --symbolic" as --force does not work? - linux

I am trying to do a ln -symbolyc link for all the .* files.
The problem is that it works first time, but second time it fails, and it looks that --force does not work
This is the code:
ln --symbolic --relative --force ./websites/web1es/.* ./websites/webtable/
This is the error:
ln: ./websites/webtable/.: cannot overwrite directory
ln: './websites/web1es/..' and './websites/webtable/..' are the same file
Does anyone have any idea?
Thanks a lot in advance for any clue!

When you specify .* in the shell, that includes . and ... If you specify a directory as the last argument, all the input files are linked into the destination directory with their same name as in the source directory.
As a result, your script is linking ./websites/web1es/.. to ./websites/webtable/... Unfortunately, the latter exists and is the parent directory of both directories, so deleting it is not possible. Moreover, as ln is telling you, the source and destination are the same file (or, in this case, directory), so even if ln could delete the destination, you'd experience data loss by doing so, so it's refusing.
Your solution should be to avoid handling . and ... For example, you could write this:
find ./websites/web1es -mindepth 1 -maxdepth 1 -name '.*' -print0 | \
xargs -0 -I {} ln -srf {} ./website/webtable
find does not enumerate . and .. here.

Related

Linux - Can't recursively delete large directories

I have a pretty big find that is supposed to delete any files/dir it finds. I just can't get it to work properly.
If I attach -exec rm -fr {} \;, at some point, I always get the following errors:
find: ‘/path/to/dir/file123.local’: No such file or directory
If I replace it with -delete, I get the following error:
find: cannot delete `/path/to/dir': Directory not empty
I looked for suggestions online but the suggestion is always the other option (replace -exec with -delete and vice-versa)
Does anyone happen to know a way to fix it without redirecting stderr to null?
Thanks ahead!
find doesn't know what your command passed to -exec does. It traverses the directory tree in this order:
find a file
execute a command on that file
if it's a directory, traverse it down
Now if the directory is removed with rm -fr, there is nothing to traverse down any more, so find reports it.
If you supply the -depth option, then the traversal order changes:
find a file
if it's a directory, traverse it down
execute a command on that file
This will eliminate the error message.
-delete implies -depth, so ostensibly it should work. However it is your responsibility to make sure the directories you want to delete are completely cleaned up. If you filter out some files with -time etc, you may end up trying to delete a directory which is not completely clean.
You could try to wrap {} in double quotes, there may have space in directry path.
-exec rm -rf "{}" \;
If I read your question well, you want to remove files, but sometimes it happens that they already have been removed by some other process, and you wonder what you should do.
Why do you think you should do anything? You want the file to be gone, and apparently it is gone, so no worries.
Obviously the corresponding error messages might be annoying, but this you can handle adding 2>/dev/null at the end of your command (redirect the error output to <NULL>).
So you get:
find ... -exec rm -fr {} \; 2>/dev/null
Edit after comment from user1934428:
I might be a good idea to drop the r switch:
find ... -exec rm -f {} \; 2>/dev/null
In that case, you should have no errors anymore:
find ... -exec rm -f {} \;

Symlink multiple files to an existing folder

I have this command:
ln -sf src/* lang/golang/src/genericc/
I want to symlink all the files in src to the existing genericc directory, but when I run the above command I get broken symlinks in the destination. Anyone know how to do this?
Symlinks created with relative paths (i.e. where the source path doesn't start with "/") get resolved relative to the directory the link is in. That means a link to "src/foo.c" in the lang/golang/src/genericc/ directory would try to resolve to lang/golang/src/genericc/src/foo.c which probably doesn't exist.
Solution: either use an absolute path to the source files, like this:
ln -sf /path/to/src/* lang/golang/src/genericc/
or, to get the * wildcard to work right with a correct command, cd to the target directory so the relative paths will work the same way during creation that they will during resolution:
cd lang/golang/src/genericc
ln -sf ../../../../src/* ./
First of all, you can try ln -s $PATH_TO_SRC/* $PATH_TO_TARGET/.
However, it might have the "Argument list too long error".
Then you can use:
find $PATH_TO_SRC/ -type f -name "*.jpg" -exec cp -s {} . \;
Because if you use ln -s with find or bash loop, it will only create an empty link. Instead, we can use cp -sto create a smylink as well.
With the -r option, ln creates a link to the actual files wherever they are:
ln -srf src/* lang/golang/src/genericc/

linux cp: how to have it follow links but not stop if a link target doesn't exist

I want to recursively copy a dir and have the targets of the links copied, but I do not want the cp to stop if a target of a link does not exist.
For example, I run this command:
cp -fprL /path/to/src_dir /path/to_dest_dir
But the first time it hits symlink where the target doesn't exist it exits:
cp: cannot stat `/path/to/non-existent/file': No such file or directory
Is there some way to get cp to silently skip these and continue on?
With the standard GNU toolchain, no, there's no way.
You could instead copy your files, keeping symlinks as symlinks, then use find -follow -type l -delete to delete the broken symlinks, and then copy again, this time following symlinks.
Of course, you could also just write a python etc. program to do the copy for you, or find all files in the original trees that are not broken symlinks and use these with cp, replacing parts of the path with the target path using sed:
find -type d|sed 's/^\(.*\)/"\1" "\/target\/\1"/g'|xargs -p mkdir
find -follow -not -type l -not -type d|sed 's/^\(.*\)/"\1" "\/target\/\1"/g'|xargs -n2 cp
sed will duplicate your found file path, prefixing it with the target directory.

Edit the contents of directory tables (Linux)

How can I edit the contents of a directory file? Since directories are just special files with a table of links to the files contained within, I should be able to view the table right?
When I open a directory in vim I can't go into insert mode to edit the links, which I assumed would be the basic available functionality, even if it didn't work.
Like Kevin said, you can't do it. What you CAN do is see symlinks and hardlinks with find, and I suppose use the ln command to do what you want from there.
Using the find command
You can see all normal files with this command...
find <DIR> -type f -links 1
You can see hardlinked files with this command...
find <DIR> -type f -links +1
To see all symlinks, you could use...
find <DIR> -type l
You can add -ls to any of these to get a more verbose output.
Finding all symlinks in current directory, non-recursively, with additional file info:
find . -type l -maxdepth 1 -ls
Using ln and unlink commands
Use ln to create links...
ln <current_file> <link_filename>
...and for symlinks...
ln -s <current_file> <shortcut_filename>
..and of course to delete a hardlink, use rm as usual...
rm <hard_link_filename>
...and for deleting a symlink....
unlink <symlink_filename>
Note: if the symlink links to a directory, be sure not to include a final "/"
This will not work.... unlink /var/www/deleteme/ if deleteme is a directory on the other end.
Hope this helps.

Copying modified files and their file structure

I'm still new to linux scripting, so this might be a bit trivial.
As part of my script, I am trying to copy all the modified files (relative to the original backup I have made) to another folder while keeping the file structure.
I have found this method:
find /SourceFolder/ -newer /BackupFOlder/ -exec cp --parents \{\} /Destination
However the above command does not work, giving me the error:
find: missing argument to 'exec'
Why doesn't this work?
I also found this:
Copy files preserving folder structure
But I want to use cp command only.
Would really appreciate some help.
The -exec option requires a ; argument to tell it where the command ends, because you could have additional find options after it.
find /SourceFolder/ -newer /BackupFOlder/ -exec cp --parents {} /Destination \;
However, a better solution would be to use rsync:
rsync -a /SourceFolder /BackupFolder
Try
tar cf - . | (cd <some other dir>; tar xfv -)

Resources