我正在尝试使用下面的函数打印所有子目录,但由于某种原因,当文件名包含空格(“”)时,会将echo
名称分为两部分。这是一个例子:
我的目录包含一个名为r1 August.request
.
输出是:
r1
August.request
我正在寻找
r1 August.request
这是我的脚本:
#!/bin/bash
function ScanFile {
for file in `ls` ; do
if [[ -d "$file" ]] ; then
cd "$file"
ScanFile
cd ..
else
echo "$file"
fi
done
}
ScanFile
答案1
SH 兼容 shell 中有所谓的 IFS 变量。 IFS 代表内部字段分隔符。此变量控制 shell 如何检测参数边界(如位置参数中的参数边界)。
默认情况下是:
set IFS=$' \t\n'
这意味着:将输入拆分为由空格、制表符和换行符分隔的标记。
您的文件由空格组成。尝试这样做:
OLD_IF="$IFS"
IFS=$'\t\n'
for file in `ls -1` ; do
# Content of your loop
done
IFS="$OLD_IFS"
这里的要点是存储以前的 IFS 值并恢复它。
编辑:添加ls -1
为每行列出一个文件,因此执行您提到的内容。
答案2
在bash中:
shopt -s globstar
ls -1d **/
答案3
您的函数解析 的未加引号的输出ls
。这意味着 shell 将在ls
.
反而:
dirwalk () {
indent=${1:-0}
for name in *; do
[ ! -e "$name" ] && continue
if [ -d "$name" ]; then
printf '%*sDir: "%s"\n' "$indent" "" "$name"
( cd "$name" && dirwalk "$(( indent + 4 ))" )
else
printf '%*sFile: "%s"\n' "$indent" "" "$name"
fi
done
}
或者,没有花哨的缩进,
dirwalk () {
for name in *; do
[ ! -e "$name" ] && continue
if [ -d "$name" ]; then
printf 'Dir: "%s"\n' "$name"
( cd "$name" && dirwalk )
else
printf 'File: "%s"\n' "$name"
fi
done
}
通过使用*
而不是 的输出ls
,我们生成了一个正确分隔的文件名列表,以便在当前目录中进行迭代,即使这些文件名包含空格。
测试-e
是为了确保我们迭代的东西确实存在。如果我们输入一个空目录,则*
不会扩展并保留为*
.在 中bash
,您可以设置nullglob
shell 选项(使用shopt -s nullglob
)来使不匹配的模式扩展为空。
通过在子 shell 中(在括号内)使用cd
,我们不必记住cd ..
返回到上一个目录。外面的环境( ... )
不会受到cd
里面的影响。
使用printf
而不是echo
我们可以更好地控制输出的格式。另请参见“为什么 printf 比 echo 更好?”。