4

I am working on a Synology NAS. I have a list of files I want to delete, listed with full path in a file called Myfiles.txt.  The file has circa 3000 lines like this:

"/volume2/NBU/Downloads/AA_To be seen/Life.Itself.2018.1080p.WEB-DL.DD5.1.H264-FGT/RARBG.txt"
"/volume2/nbU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E16.High.Stakes.Hip.Hop.WEBRip.x264-ION10.mp4"
"/volume2/NBU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E14.Time.to.Face.the.Music.WEBRip.x264-ION10.mp4"

I am using following script (testing with ls to later replace with rm -f):

#!/bin/bash
while IFS="" read -r p;
do
  ls "$p"
done < "Myfiles.txt"

Unfortunately, when I execute the script, every single loop errors out with the following message:

ls: cannot access "/volume2/NBU/Downloads/AA_To be seen/Life.Itself.2018.1080p.WEB-DL.DD5.1.H264-FGT/RARBG.txt": No such file or directory
ls: cannot access "/volume2/NBU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E16.High.Stakes.Hip.Hop.WEBRip.x264-ION10.mp4": No such file or directory
ls: cannot access "/volume2/NBU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E14.Time.to.Face.the.Music.WEBRip.x264-ION10.mp4": No such file or directory

But when I execute the line directly from the command line, it works.  For example:

ll "/volume2/NBU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E14.Time.to.Face.the.Music.WEBRip.x264-ION10.mp4"

Gives as output:

-rwxrwxrwx+ 1 Pansysadmin users 275337817 Dec 15  2018 /volume2/NBU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E14.Time.to.Face.the.Music.WEBRip.x264-ION10.mp4

Even when I execute the script with sudo, it gives the same error.

What am I overlooking?

  • The user said: ... in the file I could see the variables end on ^M, which probably means it is a dos file not a unix file. I was able to fix that via vi. And then all was well. –  Jan 03 '22 at 23:25

2 Answers2

9

The quotes are not part of the filenames. You're trying to remove files such as "file.txt" but the file is actually called file.txt.

touch "file.txt"    # shell uses quotes; name is simply file.txt
ls "file.txt"       # quotes used by shell; success
ls file.txt         # no quotes; success
ls '"file.txt"'     # outer quotes used by shell to treat word-with-quotes as literal; failure

Fix the file of names so that the filenames are correct (i.e. without double quotes surrounding them), or modify your loop to remove the incorrect parts of the data.

I've just seen your comment about trying sudo. Please don't recourse to sudo without first understanding why you might need it. (You don't, here.) Otherwise one day you may end up breaking your system because you've inadvertently bypassed the protections it's tried to offer you.

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
7

To enlarge upon roaima’s answer,

  • When you give commands to the shell, it does a lot of processing and interpretation on the command line.  For example:

    • If you type
      ls foo bar
      
      the shell runs ls with two arguments: foo and bar.  But if you type
      ls "foo bar"
      
      the shell runs ls with one argument: foo bar.
    • If you type
      rm north*
      
      the shell runs rm with many arguments, such as north1, north42, northwest, etc.  But if you type
      rm "north*"
      
      the shell runs rm with one argument: north*.
    • If you type
      echo Math tells us that 5 > 4.
      
      the shell creates a file called 4. and writes Math tells us that 5 to it.  Etc.
  • When the read command reads input, it does none of that processing.  In particular, if you read a line of input that contains special characters like *, > and ", it just puts those characters into your p variable.  Spaces and tabs normally still have some special meaning, but you’re successfully suppressing that with IFS=.  Backslash (\) normally still has some special meaning, but you’re successfully suppressing that with read -r.  So p is getting set to the filenames with " at the beginning and end.

  • Expanding the values of variables is one of the last things the shell does.  So, for example, you can do stuff like

    statement="Math tells us that 5 > 4."
    echo $statement
    

    and the shell will write Math tells us that 5 > 4. (to the terminal), because it doesn’t examine the contents of the statement variable for > characters.

    Note: the above is a bad example.  In general you should say

    echo "$statement"
    

    i.e., with quotes.

  • So, when you say

    ls "$p"
    

    the shell runs ls with an argument that includes quote characters.  It’s essentially the same as saying

    ls '"/volume2/NBU/Downloads/AA_To be seen/Life.Itself … H264-FGT/RARBG.txt"'
    

    (note the quotes within quotes).  And the names of your actual files don’t include quote characters.