`ls` 在 bash 脚本内部和外部的行为不同

`ls` 在 bash 脚本内部和外部的行为不同

我正在使用 Synology NAS。我有一个要删除的文件列表,在名为 的文件中列出了完整路径Myfiles.txt。该文件大约有 3000 行,如下所示:

"/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"

我正在使用以下脚本(测试为ls稍后替换为rm -f):

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

不幸的是,当我执行脚本时,每个循环都会出错并显示以下消息:

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

但是当我直接从命令行执行该行时,它就可以工作。例如:

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"

给出输出:

-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

即使当我使用 执行脚本时sudo,它也会给出相同的错误。

我在忽略什么?

答案1

引号不是文件名的一部分。您正在尝试删除诸如 之类的文件,"file.txt"但该文件实际上名为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

修复名称文件,使文件名正确(即文件名周围没有双引号),或者修改循环以删除数据的不正确部分。

我刚刚看到你关于尝试的评论sudosudo在未首先了解您可能需要它的原因之前,请不要求助于它。 (在这里,你不需要。)否则有一天,你可能最终会破坏你的系统,因为你无意中绕过了它试图为你提供的保护。

答案2

放大罗艾玛的回答,

  • 当您向 shell 发出命令时,它会在命令行上进行大量处理和解释。例如:

    • 如果您输入
      ls foo bar
      
      shellls使用两个参数运行:foobar。但是如果你输入
      ls "foo bar"
      
      shellls以一个参数运行:foo bar
    • 如果您输入
      rm north*
      
      shell 运行时rm带有许多参数,例如north1north42northwest等。但是如果您输入
      rm "north*"
      
      shellrm以一个参数运行:north*
    • 如果您输入
      echo Math tells us that 5 > 4.
      
      shell 创建一个名为 的文件并向 其4. 写入内容。 Math tells us that 5ETC。
  • read命令读取输入时,它不执行任何处理。特别是,如果您的read输入行包含特殊字符,例如*,>",它只会将这些字符放入您的p变量中。空格和制表符通常仍然具有一些特殊含义,但您可以使用IFS=.反斜杠 ( \) 通常仍然具有一些特殊含义,但您可以使用 成功抑制它read -rp设置为"开头和结尾的文件名也是如此 。

  • 扩展变量的值是 shell 最后要做的事情之一。例如,你可以做类似的事情

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

    shell 将写入Math tells us that 5 > 4.(到终端),因为它不会检查statement变量 内容中的> 字符。

    注意:上面是一个不好的例子。一般来说你应该说

    echo "$statement"
    

    即,带引号。

  • 所以,当你说

    ls "$p"
    

    shell 运行时ls带有一个包含引号字符的参数。这本质上是一样的

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

    (注意引号内的引号)。并且实际文件的名称不包含引号字符。

相关内容