【问题标题】:Shell recognizes files in ~ but not in ~/DocumentsShell 可以识别 ~ 中的文件,但不能识别 ~/Documents 中的文件
【发布时间】:2014-11-28 17:30:05
【问题描述】:

我正在上 Unix 课程,这是我的部分作业:

对于用户 ~/Documents 目录中的每个文件和子目录,确定该项目是文件还是目录,并使用语句中的文件名显示一条消息。

所以,我写的是这样的:

docs=`ls ~/Documents`

for file in $docs ; do
    if [ -f $file ] ; then
        echo $file "is a file."
    elif [ -d $file ] ; then
        echo $file "is a directory."
    else
        echo $file "is not a file or directory."
    fi
done

我的文档目录包括这些文件和目录:

DocList.txt  (file)
Letter       (file)
mypasswdfile (file)
samples      (directory)
things       (directory)
touchfile    (file)

所以我认为输出应该是这样的:

DocList.txt is a file.
Letter is a file.
mypasswdfile is a file.
samples is a directory.
things is a directory.
touchfile is a file.

但是,这是输出:

DocList.txt is not a file or directory.
Letter is not a file or directory
mypasswdfile is not a file or directory
samples is not a file or directory
things is not a file or directory
touchfile is not a file or directory

我觉得我应该提一下,如果我将 $docs 变量设置为 `ls ~',它将成功显示我的主目录的内容以及项目是文件还是目录。这不适用于我尝试过的其他路径。

【问题讨论】:

  • 如果您的用户名中有空格,您可能需要在这些 $file 引用周围加上引号。
  • 你真的看过ls ~/Documents的输出了吗?
  • ~/Documents/呢?
  • 提示:你从哪个目录运行这个脚本?
  • 没错。这是parsing ls 的失败之一。你应该这样做:for file in ~/Documents/*; do ...

标签: linux bash shell


【解决方案1】:

你的问题是ls只输出没有路径的文件名。

所以你的$file 得到了值

DocList.txt
Letter
mypasswdfile
samples
things
touchfile

从循环运行到循环运行。

如果您的当前目录不是~/Documents,则测试这些文件名是错误的,因为这将在当前目录中搜索,而不是在预期目录中。

完成任务的更好方法是

for file in ~/Documents/* ; do
    ...
done

这会将$file 设置为查找文件所需的每个完整路径名。

这样做后,它应该可以工作,但它很容易出错:一旦您的路径或您的一个文件开始包含空格或其他空白字符,它就会落在您的脚上。

" 放在可能包含空格等内容的变量周围是非常必要的。几乎没有理由使用没有其周围 " 的变量。

这里有什么区别?

使用[ -f $file ]file='something with spaces',使用参数-fsomethingwithspaces] 调用[。这肯定会导致错误的行为。

OTOH,使用[ -f "$file" ]file='something with spaces',使用参数-fsomething with spaces] 调用[

所以在 shell 编程中引用是非常重要的。

当然,[ -d "$file" ] 也是如此。

【讨论】:

    【解决方案2】:

    问题在于您的 ls 命令 - 您将 ls 的输出视为绝对值,例如/home/alex/Documents/DocList.txt,但是当您执行 ls ~/Documents 时,它会打印出 DocList.txt(相对文件路径/名称)。

    要获得预期的绝对行为,您可以改用find 命令:

    docs=`find ~/Documents`
    

    正如 cmets 和另一个答案中提到的,为了还能够处理文件名中的空格,您需要执行以下操作:

    docs=( ~/Documents/* )
    for f in "${docs[@]}"; do
        ...
    

    【讨论】:

    • 不,请改用 bash 数组:docs=( ~/Documents/* ); for file in "${docs[@]}"; do ... -- 其他任何东西都无法处理带有空格的文件。
    • 我不明白你的评论。如果 ~/Documents/ 中有一个名为 hello world.txt 的文件,for 循环将如何运行?
    • 它虽然工作得很好,但编辑:你是对的@glennjackman 我添加了一个带有空格的文件,它将它解释为 2 个文件,无法确定它们是文件还是目录
    • @glennjackman - glglgl 说 OP 在他们的文件中没有任何空格。您也是正确的,因为处理空格更加健壮。
    • @CharlesDuffy 是的,但简单的for file in ~/Documents/* 也可以。在写我的评论时,我不知道 OP 使用 ls - 这绝对是错误的。但是 OP 也以错误的方式使用变量,这是我想评论的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 2019-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多