我正在学习一个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
我觉得我应该提到,如果我将$ docsvariables设置为“ls〜”,它将成功显示我的主目录的内容以及项目是文件还是目录。 这不适用于我尝试过的其他path。
你的问题是, ls
只输出没有路径的文件名。
所以你的$file
获取值
DocList.txt Letter mypasswdfile samples things touchfile
从循环运行到循环运行。
如果您的当前目录不是~/Documents
,则测试这些文件名是错误的,因为这将在当前目录中进行搜索,而不是在目标目录中进行搜索。
一个更好的方式来完成你的任务是
for file in ~/Documents/* ; do ... done
这将设置$file
到每个需要找到你的文件的完整路径名。
这样做后,它应该工作,但它是非常容易出错的:一旦你的路径或你的一个文件开始有一个空间或其他空白字符,它会落在你的脚上。
把"
可能包含某些东西的变量放在变量的周围等等”是非常重要的,几乎没有理由使用没有周围变量的变量。
这里有什么区别?
用[ -f $file ]
和file='something with spaces'
, [
用参数-f
, something
, with
, spaces
和]
调用。 这肯定会导致错误的行为。
OTOH,带[ -f "$file" ]
, file='something with spaces'
, [
用参数-f
调用, something with spaces
]
。
所以在shell编程中引用是非常重要的。
当然,这同样适用于[ -d "$file" ]
。
问题在于你的ls
命令 – 你把ls
的输出视为绝对的,例如/home/alex/Documents/DocList.txt
,但是当你做DocList.txt
ls ~/Documents
,会打印出DocList.txt
(一个相对的文件路径/名字)。
要获得预期的绝对行为,可以使用find
命令:
docs=`find ~/Documents`
正如在评论和另一个答案中提到的,为了也能够处理文件名中的空白,你需要做一些事情:
docs=( ~/Documents/* ) for f in "${docs[@]}"; do ...