Linux update link file

I have a web app that has a bunch of symbolic links in subdirectories throughout it. I need to move the app to another directory structure, and I need to update all the symlinks to point to the new path. For example: Old Dir: /home/user/public_html/dev
New Dir: /home/user/public_html/qa
Old Symlink: /home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/dev/images
New Symlink: /home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/qa/images The problem is that there’s a lot of these scattered throughout various directories. How can I recursively search from the root and recreate all symlinks pointing to /dev/ with /qa/ ?

4 Answers 4

This bash command should do it for you:

find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' -printf 'ln -nsf "$(readlink "%p" | sed s/dev/qa/)" "$(echo "%p" | sed s/dev/qa/)"\n' > script.sh 

It uses find to identify all files in the qa directory that are symbolic links with a target that’s in the dev directory, and for each one, it prints out a bash command that will replace the link with a link to the equivalent path in qa/ . After you run this, just execute the generated script with

You might want to examine it manually first to make sure it worked.

Here’s a more verbose version of the above find command for easier reading (though I wouldn’t necessarily write it this way in practice):

SRC_DIR="/home/user/public_html/qa" OLD_TARGET="/home/user/public_html/dev" SUB="s/dev/qa/" find $SRC_DIR -type l \ -lname "$OLD_TARGET/*" -printf \ 'ln -nsf "$(readlink "%p"|sed $SUB)" "$(echo "%p"|sed $SUB)"\n'\ > script.sh 

Источник

A big thank you for asking, accepted answer solves it for me. I don’t see it in the «renaming file works. » Q&A.

1 Answer 1

I heard that symlinks can’t be edited. So do I have to create new symlinks and then overwrite the existing ones?

Symlinks can’t be edited, that is correct. You can replace symlinks to files in a single operation with the -f option to ln , and if you add -T you can process symlinks to directories in the same way:

ln -sfT /data/Tim/dir1 symlink1 

will create symlink1 pointing to /data/Tim/dir1 , replacing any existing symlink (or file!) named symlink1 .

how can I get the pathname of the directory pointed to by a symlink, and then use some text processing programs to replace the old name of the ancestral directory in the pathnames with its new name, and create a symlink pointing to the directory with a new pathname?

realpath will give you the absolute path to which the symlink points. To process your symlinks:

for symlink in *; do if [ -L "$" ]; then origpath="$(realpath "$")" && ln -sfT "$" "$" fi done 

This retrieves the path of each file in the current directory (so I’m assuming all symlinks in the current directory need fixing) and relinks it, replacing the first occurrence of home with data . Using && ensures that the symlink is only replaced if realpath succeeded (it fails if the target doesn’t exist).

Читайте также:  Установка steam kali linux

Источник

My basic understanding of a symlink is that it’s a special file, a file that contains a string path to another file. The kernel’s VFS abstracts a lot of that away but is there any reason why symlinks seem to be impossible to edit? In other words: Can I edit a symlink? If not, why not? I do understand that there are various ways of replacing symlinks (two alternatives are currently in the answers section) but it would be interesting to get an explanation on why replacement seems to be the only way to deal with symlinks. Why can’t you just change where they point?

Your understanding is a bit limited; the only reason it’s called a ‘file’ is because there’s no better word for it.

Unlike the embarrassing atrocity that is the windows variant, posix-style symbolic links operate on/in the filesystem layer itself. The only way to edit one would be to edit the filesystem directly — and it’s generally not worth it.

@Shadur .lnk files are not really symlinks to begin with (and NTFS has had proper symlinks since Vista); they’re more like shortcuts for executing commands, whether that is changing to a specific folder or starting a program with specific arguments and with a certain CWD.

7 Answers 7

ln -s /location/to/link linkname # . ln -s /location/to/link2 newlink mv -T newlink linkname 

linkname is accessible throughout the process.

That does get you the atomic replacement, though you still are doing a replace rather than edit ( new link has a new inode number ).

@psusi I completely agree, it’s just a technically slightly better option than the other answer in some scenarios.

If you’re redirecting the link to another destination then changing it’s inode number seems like a small change.

That assumes linkname is not a symlink to a directory. Use the -T option to mv if on GNU or -h if on FreeBSD to avoid that. Note that like ln -sf that does not preserve the permissions of the link (on systems where they are significant).

Another solution for change symlink for directory is to use -n options e.g.: ln -sfn DESTINATION_DIRECTORY LINK_NAME . Read more on askubuntu.com/a/186227/69004

If by edit, you mean to change the file it points to, then yes you can:

$ ln -s .bashrc test $ ls -al test lrwxrwxrwx 1 pascal pascal 7 2009-09-23 17:12 test -> .bashrc $ ln -s .profile test ln: creating symbolic link `test': File exists $ ln -s -f .profile test $ ls -al test lrwxrwxrwx 1 pascal pascal 8 2009-09-23 17:12 test -> .profile 

The -f parameter ( —force ) when passed to ln it causes it to call the unlink() system call right before symlink()

I think it’s questionable if this can be regarded as «edit», since unlink();symlink(); is not atomic, so there is a tiny tiny amount of time during which the link does not exist.

Читайте также:  Линукс копирование файлов windows

@mauro.stettler Yes, you are right. But I guess that this depends on your perspective. If you take only the end result into account, then maybe you could consider it as edited, no other things considered.

The quoted section from the Unix Time Sharing System paper describes hard links. These are entirely different from the symbolic links (symlinks) the OP asked about.

Note that it assumes test ‘s target is not a directory. Otherwise ln -s -f .profile test would create a .profile symlink in that directory. GNU ln has a -T option to avoid that.

Symbolic links need to be modified atomically. If you’re halfway through writing them, they won’t work. The content of a symbolic link is pretty small (at most 4095 characters on Linux: the maximum length of a path to a file), so there would be little point in editing part of a symbolic link at the kernel level. Therefore the kernel does not offer any interface to edit a symbolic link, only an interface to create a new one, the symlink system call (plus the generic interface unlink to remove any file).

The symlink system call only creates a new symbolic link, it does not remove any existing file. This is annoying, but consistent with other system calls to create files such as open (which can create a new file or truncate an existing file, but not replace an existing file by a newly-created file) and mkdir .

In the shell, as you’ve discovered, while you can’t replace a symbolic link atomically with the ln command ( ln -sf unlinks the previous file then creates the symbolic link), you can do it by first creating a symbolic link under a temporary name and then moving it into place.

tmp=$(TMPDIR=$(dirname -- "$link") mktemp) ln -sf -- "$target" "$tmp" mv -f "$tmp" "$link" 

Источник

Now I want to change the location that the symlink links to. How do I do that? is there a way to do it without deleting it first?

10 Answers 10

You could create the new link with a different name, then move it to replace the old link.

ln -s /location/to/link linkname 
ln -s /location/to/link2 newlink mv newlink linkname 

If newlink and linkname are on the same physical device the mv should be atomic.

FYI, i’m sure this works on some os but this didn’t work for me, the move operation just removed the ‘new’ link instead of replacing the old one. i still had to rm first.

@pstanton You mean that mv newlink linkname caused the newlink file to be deleted, but didn’t overwrite the linkname file? Did it do this silently? That seems extremely mysterious.

mv newlink linkname will move your newlink into linkname if they are directories. So this method is not 100% perfect.

Читайте также:  Linux distributions что это

Try ln -sf new_destination linkname .

This is non-atomic, though. See my answer for details. I’m not clear whether that’s the poster’s concern or not.

This also won’t work with symlinks pointing to directories. It will just create a new symlink inside the old target directory.

Just change the symlink target:

# ln -sfT /path/to/new/target linkname

This is an instant, atomic change.

-T, —no-target-directory treat LINK_NAME as a normal file always you can brew install coreutils and access the GNU versions with a g prefix, like gln if you want the GNU versions on macOS. saves a lot of headache when there are subtle differences like this.

If the symlink targets are directories, you need to add the -T flag to the mv command, otherwise it moves the new symlink in to the target directory of the old symlink.

Example of atomically switching a website to a new version:

Original setup — website is stored in www1 directory, vhost pointing at www symlink:

Browse to website, see old version.

Put new website files in new www2 directory.

Set up new symlink to new website:

Move www symlink to directory of new website:

Browse to website, see new version immediately.

So apparently the version of mv on my NAS’s microkernel doesn’t support the -T argument. Any alternative suggestions for doing this atomically?

Try creating the symlink with the -f (force) flag. That seems to work. See the answer below: ln -sf new_destination linkname

On OSX, the man page for ln says you can do it like this

ln -shf /location/to/link link name 
The options are as follows: 
 -F If the target file already exists and is a directory, then remove it so that the link may occur. The -F option should be used with either -f or -i options. If none is specified, -f is implied. The -F option is a no-op unless -s option is specified. -h If the target_file or target_dir is a symbolic link, do not follow it. This is most useful with the -f option, to replace a symlink which may point to a directory. -f If the target file already exists, then unlink it so that the link may occur. (The -f option overrides any previous -i options.) -i Cause ln to write a prompt to standard error if the target file exists. If the response from the standard input begins with the character `y' or `Y', then unlink the target file so that the link may occur. Other- wise, do not attempt the link. (The -i option overrides any previous -f options.) -n Same as -h, for compatibility with other ln implementations. -s Create a symbolic link. -v Cause ln to be verbose, showing files as they are processed. 

Источник

Оцените статью
Adblock
detector