Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am keeping my dotfiles under version control and the script deploying them creates hard links. I also use etckeeper to put my /etc under version control. Recently I have gotten warnings like this:

warning: hard-linked files could cause problems with bzr

A simple copy (cp filename.ext filename.ext) will not work:

cp: `filename.ext' and `filename.ext' are the same file

Renaming/moving a file - except across volumes - also doesn't break the hard-link.

So my question is: is there a way to break a hard-link to a file without actually having to know where the other hard-link/s to that file is/are?

share|improve this question
1  
The "rm" command breaks hard links. –  Johan Mar 4 '13 at 12:53

6 Answers 6

up vote 4 down vote accepted
cp -p filename filename.tmp
mv -f filename.tmp filename

Making it scriptable:

dir=$(dirname -- "$filename")
tmp=$(TMPDIR=$dir mktemp)
cp -p -- "$filename" "$tmp"
mv -f -- "$tmp" "$filename"

Doing the copy first, then moving it into place, has the advantage that the file atomically changes from being a hard link to being a separate copy (there is no point in time where filename is partial or missing).

share|improve this answer
    
Makes sense. +1 ... good thinking about the --, too –  0xC0000022L Mar 6 '13 at 0:49
    
the first time I read this question i thought you didn't use mktemp, so I wrote a similar answer ~_~ –  pqnet Aug 6 at 12:12

You probably mean that you want to split the hard-link off to a separate, independent file.

mv hardlink tempname && cp tempname hardlink && rm tempname

A hardlink is the connection between an entry in the directory and the inode block on the disk.

inodes store file meta-data, and for small files, some file systems stores data in the inode, otherwise pointers to the data blocks, and for very large files indirect and double-indirect lists of pointers to disk allocation units.

Regardless, the connection between the file name (Which is what the ls command produce) and the inode block which stores this meta-data, is called a hard link.

Having multiple hard links to a single file means the same inode referenced by more than one directory entry, possibly in different directories (on a single file system)

rm deletes the file name entry from the directory. Once an inode is no longer referenced by any files, its space is freed up for use by other files.

share|improve this answer
    
Indeed. This is what the cp and mv examples implied. So no way around using a temporary file, I see. –  0xC0000022L Mar 4 '13 at 13:20
    
@0xC0000022L, No, inodes don't contain pointers to other inodes. Just to data blocks (or they can double as data space if the object is small). –  vonbrand Mar 4 '13 at 13:26
3  
Make sure the permissions and other data is preserved when copying, i .e. use cp -a (at least GNU coreutils). –  vonbrand Mar 4 '13 at 13:29
    
@0xC0000022L, if you look carefully, there is just a temporary name for the orginal file, a new file is created only in the last step. –  vonbrand Mar 4 '13 at 13:32
    
@vonbrand They can indeed, depending on what file system is being used. –  Johan Mar 4 '13 at 13:35

The command you're looking for is unlink

share|improve this answer
    
Perhaps my question was not clear, but by "in-place" and the examples with cp and mv I meant to make clear that I wish the file to exist afterward. –  0xC0000022L Mar 4 '13 at 13:21
    
Ah, I didn't find that clear, no. You should go with Johan's answer, then. –  Jenny D Mar 4 '13 at 13:23

Put this at the end of your ~/.bashrc file.

delink () { tmpfile="$1$(date)"; cp -a "$1" "$tmpfile"; mv "$tmpfile" "$1"; }

Run it like this

delink filename
share|improve this answer

The best way to do it with a bash script would be something like this:

if [ -f "$1" ] ; then
dir="$(dirname -- "$1")"
tmpfile="$(mktemp --tmpdir="$dir")"
cp --preserve=all -f -- "$1" "$tmpfile"
mv -f -- "$tmpfile" "$1"
fi

points to note:

  • check if the file is a regular file before trying to copy it
  • keep the old file in place until the copy is ready
  • use mktemp to generate a file which is guaranteed not to exist
  • use -f to force overwrite and --preserve=all to keep metadata as similar as possible to the original file
  • use -- and " to quote paths containing spaces and/or beginning with -

Doing the replacement without creating a temporary file isn't possible with current (3.16) linux system calls: while it is possible to overwrite a file atomically (i.e., remove the old file and replace with a new one as a single operation), it is not possible to do so with a file which has no name on the filesystem (i.e. a temporary file created using the O_TMPFILE flag of open function) because the rename function require a filename as input (there is no version of rename which takes as input a file descriptor - see here for details)

share|improve this answer
    
Note that you failed to quote the name in your dirname and mktemp calls. Fixed that for you... –  derobert Aug 6 at 12:10
    
@derobert oh thank you, but this won't work since there are nested double quotes... need another fix! Kinda hate bash –  pqnet Aug 6 at 12:13
    
It'll work because of the $( ... )-style command substitution. One reason its nicer than ` ... `-style. –  derobert Aug 6 at 12:15
    
@derobert nice, didn't know that. Also, how can you use ` inside inline code tags? –  pqnet Aug 6 at 12:20
    
You can escape them with backslashes. So to get ` you put in: `\`` (of course, I double-escaped that to get it to show you what you type). –  derobert Aug 6 at 12:22

If your are looking for all the filename who are hardlink to this file then you can use:

find -samefile myknowhardlinkfile

also ls -il myknowhardlinkfile will show you the number of filename hardlinked to the same inode (third field).

101612442 -rw-rw-r--. 2 me me 0 Aug  5 07:07 myknowhardlinkfile
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.