![`ls` 在 bash 脚本内部和外部的行为不同](https://linux22.com/image/200481/%60ls%60%20%E5%9C%A8%20bash%20%E8%84%9A%E6%9C%AC%E5%86%85%E9%83%A8%E5%92%8C%E5%A4%96%E9%83%A8%E7%9A%84%E8%A1%8C%E4%B8%BA%E4%B8%8D%E5%90%8C.png)
我正在使用 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
修复名称文件,使文件名正确(即文件名周围没有双引号),或者修改循环以删除数据的不正确部分。
我刚刚看到你关于尝试的评论sudo
。sudo
在未首先了解您可能需要它的原因之前,请不要求助于它。 (在这里,你不需要。)否则有一天,你可能最终会破坏你的系统,因为你无意中绕过了它试图为你提供的保护。
答案2
放大罗艾玛的回答,
当您向 shell 发出命令时,它会在命令行上进行大量处理和解释。例如:
- 如果您输入
shellls foo bar
ls
使用两个参数运行:foo
和bar
。但是如果你输入
shellls "foo bar"
ls
以一个参数运行:foo bar
。 - 如果您输入
shell 运行时rm north*
rm
带有许多参数,例如north1
、north42
、northwest
等。但是如果您输入
shellrm "north*"
rm
以一个参数运行:north*
。 - 如果您输入
shell 创建一个名为 的文件并向 其echo Math tells us that 5 > 4.
4.
写入内容。Math tells us that 5
ETC。
- 如果您输入
当
read
命令读取输入时,它不执行任何处理。特别是,如果您的read
输入行包含特殊字符,例如*
,>
和"
,它只会将这些字符放入您的p
变量中。空格和制表符通常仍然具有一些特殊含义,但您可以使用IFS=
.反斜杠 (\
) 通常仍然具有一些特殊含义,但您可以使用 成功抑制它read -r
。p
设置为"
开头和结尾的文件名也是如此 。扩展变量的值是 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"'
(注意引号内的引号)。并且实际文件的名称不包含引号字符。