I use a script to link some of the files I download to a different directory. When there are - in the file name, ln - s wont read the path correctly, even though the variable will be logged correctly to the log file I use. for f in ${AVIFILES}do        BaseAviName=$(basename $f .avi)        aviMp4name='$targetdir/$BaseAviName.mp4'        linkAviFile='$targetdir/$f'        downloadedFile=$('$theFile/$f')        ln -s $downloadedFile $linkAviFile >>$logPath 2>&1        echo fileIs:  $f ,linkAviFile is $linkAviFile ,BaseAviName: $BaseAviName '$aviMp4name: ' $aviMp4name '$downloadedFile: ' $downloadedFile >> $logPath   doneThat's the error message from ln:ln: failed to create symbolic link '/home/user/Videos/TVEpisodes/Parks and Recreation/Parks.and.Recreation.S03E01.DVDRip.XviD-REWARD.avi' -> : No such file or directoryEven though the variable downloadedFile is logged with the correct path:'/home/user/Downloads/Parks And Recreation - Season 3 - DVDRip-REWARD/Parks.and.Recreation.S03E01.DVDRip.XviD-REWARD.avi'It seems, that for some reason, that when $downloadedFile is expanded for ln to work with it, ln will omit part of the filename, from the first - to the next / ( - Season 3 - DVDRip-REWARD). I can't find a good reason why this happens, and want to avoid it, any suggestions...EDIT: I rewrote the script and the problem disappeared. Thanks to anyone who helped
ln -s removes part of a file name, when filename is passed as a variable
bash;shell;quoting;ln
Even though the variable downloadedFile is logged with the correct path:'/home/user/Downloads/Parks And Recreation - Season 3 - DVDRip-REWARD/Parks.and.Recreation.S03E01.DVDRip.XviD-REWARD.avi'That's evidently not the correct path: it has extra ' characters at the beginning and at the end. You can see that in the error message from ln:ln: failed to create symbolic link '/home/user/Videos/TVEpisodes/Parks and Recreation/Parks.and.Recreation.S03E01.DVDRip.XviD-REWARD.avi' -> : No such file or directoryThe error message has the file name inside single quotes, and there are extra ' (ASCII single quotes) characters at the beginning and at the end.The problem in your script is obvious: you're adding extra ' characters when defining aviMp4name, linkAviFile and downloadedFile. Don't do that.for f in ${AVIFILES[@]}do    BaseAviName=$(basename -- $f .avi)    aviMp4name=$targetdir/$BaseAviName.mp4    linkAviFile=$targetdir/$f    downloadedFile=$($theFile/$f)    ln -s -- $downloadedFile $linkAviFile >>$logPath 2>&1    echo fileIs:  $f ,linkAviFile is $linkAviFile ,BaseAviName: $BaseAviName '$aviMp4name: ' $aviMp4name '$downloadedFile: ' $downloadedFile >> $logPath   doneIn the shell source syntax, single quotes delimit literal strings, for example a='hello world!' sets the variable a to the 12-character string hello world!. If you put single quotes into a variable, you get single quotes back: a='hello world!' sets a to the 14-character string 'hello world!'.The key thing to remember with quotes in shell scripts is to put double quotes around variable expansions, e.g. ln -s -- $downloadedFile $linkAviFile. Code like ln -s -- $downloadedFile $linkAviFile would split the values of the variables downloadedFile and linkAviFile at whitespace characters and would interpret each piece as a wildcard pattern. Those double quotes are part of the shell source syntax, they're interpreted by the parser. Putting quotes into a variable's value won't solve anything.Also note that if a file name begins with a -, it will be interpreted as an option by the command. To avoid this, when you have file names in variables, pass the argument -- to the command after all options and before all file names (you can omit -- if you're sure the file names don't begin with -, for example if you know they're absolute paths). -- means no more options after this point.Note that ${AVIFILES} would, like any other unquoted expansion, split the value of the variable at whitespace. To store multiple file names in a variable, make it an array instead of a string; this requires ksh, bash or zsh, it doesn't work in plain sh:AVIFILES=(foo.avi bar.avi file name with spaces.avi)