0

In ubuntu Linux, I have a bunch of abominably broken symlinks like:

$ ls -l setup.conf
lrwxrwxrwx 1 ont ont 27 Aug 19 15:26 setup.conf -> '# Source it'$'\r''. ../setup.conf'

They are the result of an attempt to replace all symlinks in a project with a comment and a source call (". ../setup.conf") of the target file. They are all really text files (the example containing: "# Source it\n. .../setup.conf") with the symlink bit. This was done using git and windows.

One theoretical fix would be to just remove the "symlink bit" and keep the resulting textfile as is, but I see no way of doing that (chmod and other tools sees it as a "dangling symlink" and refuses to operate on the text-file itself).

Another fix would be to manually create a new file, with contents as the above as taken from the ls command. I'd rather not resort to that, as it is tedious and error prone, and the files are not identical).

EDIT: ADDED: I want to end up with a regular file named setup.conf whose contents are "# Source it<newline>. ../setup.conf'"

6
  • Please edit your question and show us the result you are expecting. I can't tell if you want to have a file named # Source it'$'\r''. ../setup.conf' or if you want to have a file named setup.conf whose contents are # Source it'$'\r''. ../setup.conf' or something else.
    – terdon
    Aug 19, 2021 at 14:56
  • There's no way but to create new files. find .... -type l -name setup.conf -exec sh -c 'readlink "$1" > "$1.new" && mv "$1.new" "$1"' sh {} + (untested)
    – user313992
    Aug 19, 2021 at 15:12
  • 2
    There's no such thing like "removing the symlink bit" any more than removing the directory bit from a file.
    – user313992
    Aug 19, 2021 at 15:15
  • "This was done using git and windows" ... Git stores symlinks that way internally, but that isn't something you are allowed to do with tools external to git.
    – muru
    Aug 19, 2021 at 15:37
  • @UncleBilly, technically, one could hack the filesystem to modify the "mode" field in the inode, the file type is usually there in the high part of the file mode bits (and definitely is in ext4). But you're right, it can't be done using the usual userspace tools, and filesystem may have special processing for symlinks, so the result of such a hack might be interesting in the wrong ways too... :)
    – ilkkachu
    Aug 19, 2021 at 17:46

1 Answer 1

1

I'm not entirely sure whether you want to fix the symlinks or replace them with text files. This solution replaces the symlinks with text files:

find -type l -exec bash -c '
    for f in "$@"
    do
        t=$(readlink "$f")
        rm -f "$f"
        printf "%s\n" "$t" >"$f"
    done
' _ {} +

You can test non-destructively by removing the rm and amending the printf to write to "$f.tmp.txt" instead of "$f". (Just remember to remove the .tmp.txt text files afterwards.)

If you want the \r replaced with \n for easier readability you can do that too:

printf "%s\n" "${t//'$'\r/\n''}" >"$f"     # non-POSIX
printf "%s\n" "$t" | tr "\r" "\n" >"$f"    # POSIX
2
  • 1
    Better do it with readlink -n "$f" > "$f.new" && mv "$f.new" "$f" (instead of command subst, rm and printf) because 1. it will preserve the contents of the symlink better and 2. it will only remove the broken symlink after its content has been saved.
    – user313992
    Aug 19, 2021 at 16:08
  • @UncleBilly I thought about that but decided I didn't want to assume "$f.new" didn't exist, and going through the palaver of using something like mktemp didn't appeal
    – roaima
    Aug 19, 2021 at 16:11

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.