I have a file and a symlink:

file: ~/${USER_HOME}/blabla/.cheatsheet
symlink: ~/.cheatsheet (is linked to file above)

Now in my script I do some operations with the file, e.g. add a line and sort the file alphabetically and move it:

addOneCommand() {
  # add it to the file
  echo "${cmd}" >> "${file}"
  # sort file instantly
  cat "${file}" | sort > "${file}".tmp
  mv "${file}".tmp "${file}"

But the real file behind the symlink doesn't get affected by the script (e.g. not sorted alphabetically). What can I do to work with "symlinked files" in bash scripts?



The point is, that you create a new file ${file}.tmp, that is now not a symlink, then rename.

You might try

cat "${file}".tmp >"${file}"
rm "${file}".tmp

instead of

mv "${file}".tmp "${file}"

If you don't mind the race condition.

P.S.: If I understand your intention correctly, you might want sort -u instead of plain sort

  • ah ok - that's it - thanks :) – m1well Mar 5 at 15:40

Your issue is that you're using mv, which will replace the symlink.

You can use a number of other approaches (see Eugen Rieck's answer for one), but fundamentally, you need to reuse the symlink, not replace it.

sponge is a good tool that will also allow you to remove handling of the *.tmp file as well:

With a file a, that is symlinked from b:

$ echo -e "3\n1\n2" > a
$ ln -s a b
$ ls -l
total 1
-rw-r--r-- 1 attie attie 6 Mar  5 15:44 a
lrwxrwxrwx 1 attie attie 1 Mar  5 15:44 b -> a

You can sort and rewrite a via b, without affecting the symlink:

$ cat b | sort | sponge b
$ ls -l
total 1
-rw-r--r-- 1 attie attie 6 Mar  5 15:44 a
lrwxrwxrwx 1 attie attie 1 Mar  5 15:44 b -> a
$ cat b

You can find the real file behind the symlink using the readlink or realpath commands.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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