0
#!/bin/bash
for i in instances/*; do
        #echo $i
        if [[ -d "${i}/.minecraft/" ]]; then
                echo "${i}/.minecraft/"
                if [ -h "${i}/.minecraft/saves" ]; then
                        rm -f "${i}/.minecraft/saves"
                else rm -rf   "${i}/.minecraft/saves";
                fi
                ln -s saves '"'${i}/.minecraft/saves'"'
        fi
done

this is my script for linking up the saves in my PolyMC setup. the problem is that the code doesnt work if DIRECTORY has a space:

instances/1.19 Sodium/.minecraft/ this has the following output:

ln: target 'Sodium/.minecraft/saves"': No such file or directory

also removing '"' still has the same error

1 Answers1

0

As everyone already commented, it's not about removing the '"' but to quote your $i inside double quotes. Nor is it a random combination of " and ' to make it work.

Explanations :

When i contains a space like : i="1.19 Sodium" (here the double quotes are delimiters, not characters of the string),

the line ln -s saves '"'${i}/.minecraft/saves'"'

is seen as :

ln -s saves '"'1.19 Sodium/.minecraft/saves'"'

In this context, single quotes are string delimiters, while double quotes are any (unwanted) characters in the string.

It is read as :

  1. The word ln,
  2. A field separator,
  3. The word -s,
  4. A field separator,
  5. The word saves,
  6. A string (delimited by single quotes) of one character " concatenated to the word 1.19,
  7. The space (coming from i) interpreted (since outside quotes) as a field separator,
  8. The word Sodium/.minecraft/saves concatenated to a string (delimited by single quotes) of one character ".

Then it's exactly equivalent to : ln -s saves '"1.19' 'Sodium/.minecraft/saves"'

Which is not what you want, and why the error message says Sodium/.minecraft/saves" does not exist.

As @tkausl commented, the solution is "${i}/.minecraft/saves" (or without the braces "$i/.minecraft/saves").

With this, when i contains a space like : i="1.19 Sodium",

the line ln -s saves "$i/.minecraft/saves"

is seen as :

  • ln -s saves '1.19 Sodium/.minecraft/saves',
  • or (equivalent) ln -s saves "1.19 Sodium/.minecraft/saves",
  • or (equivalent) ln -s saves 1.19\ Sodium/.minecraft/saves.

With the correction, any space in i will no longer be interpreted as a field separator because i is in a string delimited by double quotes.

Conclusion: Never use non-quoted variables (even echo "$i" instead of echo $i).

syme
  • 447
  • 1
  • 6
  • 12
  • 1
    Just to note, the single quotes are not string *delimiters*. They (and double quotes) are just a form of bulk escaping; every character inside the quotes is treated as if it were preceded by a backslash (with some exceptions inside double quotes). – chepner Jul 16 '22 at 22:50
  • @chepner Yes I should have emphasized that it wasn't in a potential technical word sense that I was using it (I used italic for "field separator" only). I didn't know how else to say it in this context. Example of not string delimiters: `cmd0 "$(cmd1 "$var2")"` :-) – syme Jul 16 '22 at 23:02