命令在 CLI 中有效,但在 bash 中无效

command works in CLI but not in bash

在 bash 中做一个简单的阅读:

list.txt的内容:
/foo/bar/mydirectory/myfile.jpg
/foo/bar/mydirectory/deletedfile.jpg
/foo/bar/pictures\of\coffee\cups/coffee-cup-42.jpg

#!/bin/bash

file="/foo/bar/list.txt"

while read -r line; do

    echo "VALUE OF LINE VARIABLE IS: $line"
    echo "COMMAND LINE IS: find -f $line"
    find -f $line
    # either file found, or "no such file" error
    done <$file

脚本输出:

dumbjoe$ ./read-test.sh
行变量的值是:/foo/bar/mydirectory/myfile.jpg
命令行是:find -f [=62= .jpg
/foo/bar/mydirectory/myfile.jpg 找到文件
行变量的值是:/foo/bar/mydirectory/deletedfile.jpg
命令行是:find -f /foo/bar/mydirectory/deletedfile.jpg
find:/foo/bar/mydirectory/deletedfile.jpg:没有那个文件或目录 找不到文件
行变量的值是:/foo/bar/pictures\ of\ coffee\ cups/coffee-cup-42.jpg
命令行是:find -f /foo/bar/pictures\ of \ coffee\ cups/coffee-cup-42.jpg
find: /foo/bar/pictures\: 否这样的文件或目录
find: of\: 没有这样的文件或目录
find: coffee\: 没有这样的文件或目录
find: cups/coffee-cup-42.jpg: 没有这样的文件或目录 WHAT???

运行终端中的命令
dumbjoe$ find -f /foo/bar/pictures\of\coffee\cups/coffee-cup-42.jpg
/foo/bar/pictures\ of\ coffee\ cups/coffee-cup-42.jpg 找到文件

为什么这在脚本中不起作用??

编辑:最终我所追求的是下面,我迷路的地方是变量“多转义”:

file=$LISTOFFILES

while IFS= read -r line

    do
    
    let "FILESTESTED+=1"
    
    FOUND="$(find -f $line)"
    
    # if file is not found, ignore the error
    exec 2> /dev/null
    
    # if file is found:
  
        if [ "$FOUND" == "$line" ]
            then
        
                echo "FOUND: $line" >> $REPORT
        
                FILESIZE="$(find $line -exec ls -l {} \; |  awk '{ print  }')"
    
                echo "SIZE is: $FILESIZE" >> $REPORT
                echo "-----------------------------------" >> $REPORT
    
                let "SPACETOTAL= SPACETOTAL + FILESIZE"
                let "FILES_FOUND_COUNT+=1"

        fi
    done <$file 

如果路径中没有空格,所有这些都有效。

看起来像是一个转义问题,可以试试 find -f '$line'

同时更改您的#!到 #!/bin/bash -x 你会得到一堆有用的调试信息。

您不需要转义输入文件中的空格,因为 shell 不会处理它们。直接引用参数展开即可。

将以下内容放入 list.txt:

/foo/bar/mydirectory/myfile.jpg
/foo/bar/mydirectory/deletedfile.jpg
/foo/bar/pictures of coffee/coffee-cup-42.jpg

然后将脚本更改为

#!/bin/bash

file="/foo/bar/list.txt"

while IFS= read -r line; do

  echo "VALUE OF LINE VARIABLE IS: $line"
  echo "COMMAND LINE IS: find -f $line"
  find -f "$line"
  # either file found, or "no such file" error
done < "$file"

实际文件路径是 /foo/bar/pictures of coffee cups/coffee-cup-42.jpg(没有反斜杠)。

这个:

find -f /foo/bar/pictures\ of\ coffee\ cups/coffee-cup-42.jpg

相当于:

find -f '/foo/bar/pictures of coffee cups/coffee-cup-42.jpg'

有效。 (反斜杠只是一种引用机制,类似于单引号或双引号。)

相比之下,这个:

variable='/foo/bar/pictures\ of\ coffee\ cups/coffee-cup-42.jpg'
find -f $variable

相当于:

variable='/foo/bar/pictures\ of\ coffee\ cups/coffee-cup-42.jpg'
find -f '/foo/bar/pictures\' 'of\' 'coffee\' 'cups/coffee-cup-42.jpg'

find 发送了太多单独的参数,其中一些参数末尾有虚假的反斜杠;所以命令不起作用。

主要问题是反斜杠是您键入 Bash 命令时的一个特征。它们在脚本中的工作方式与您在 shell 中键入时的效果一样好,但它们仅在实际位于命令本身中时才有效,而不仅仅是在您传递给命令的变量中。

第二个问题是 Bash 有一个奇怪的功能,称为“分词”,如果您的变量包含 whitespace 并且您没有用双引号引起来,它找到 space 并将其拆分为单独的参数。恕我直言,这是一个糟糕的功能,但它是由 POSIX 指定的,我不希望它永远改变。幸运的是,有一个简单的解决方法,即:总是 用双引号括起变量扩展。

所以,要解决这个问题:

  1. 修改您的文件以删除不属于实际文件路径的虚假反斜杠。
  2. find -f "$line" 而不是 find -f $line