我正在尝试编写一个 shell 脚本,列出目录(和子目录)中某些类型的文件。我正在努力解决递归部分。
这是我所拥有的:
#!/bin/sh
#download dir
DOWNLOADING_DIR=/Users/richard/Downloads
echo "Starting Script..."
for FILE in $DOWNLOADING_DIR/*
do
if [ -d "$FILE" ]
then
echo "...Checking Directory "$FILE
for DFILE in $FILE/*
do
echo "Found file ... $DFILE"
done
else
echo "Found file ... $FILE"
echo ""
fi
done
问题是当它找到目录时,它在目录中找不到任何文件名。它只列出子目录名称,而不列出子目录中的文件。它适用于第一个目录中的文件。
我需要这个脚本来搜索 .txt 或 .doc 文件并将它们移动到另一个目录。
答案1
你的脚本是不是递归,因为它不调用自身。
这是一个变体,它以递归方式实现类似的东西:
#!/bin/bash
walk_dir () {
shopt -s nullglob dotglob
for pathname in "$1"/*; do
if [ -d "$pathname" ]; then
walk_dir "$pathname"
else
printf '%s\n' "$pathname"
fi
done
}
DOWNLOADING_DIR=/Users/richard/Downloads
walk_dir "$DOWNLOADING_DIR"
该函数walk_dir
将目录路径名作为其唯一参数并迭代其内容。如果找到目录,它会递归地调用自身来遍历该子目录。
.txt
修改此命令以查找文件名后缀为 或的文件.doc
:
#!/bin/bash
walk_dir () {
shopt -s nullglob dotglob
for pathname in "$1"/*; do
if [ -d "$pathname" ]; then
walk_dir "$pathname"
else
case "$pathname" in
*.txt|*.doc)
printf '%s\n' "$pathname"
esac
fi
done
}
DOWNLOADING_DIR=/Users/richard/Downloads
walk_dir "$DOWNLOADING_DIR"
请注意,上面的“文件”实际上指的是不是目录或目录符号链接的任何内容,这可能与目录不同。常规文件。通过在 中设置dotglob
和nullglob
shell 选项bash
,我们能够找到隐藏的路径名,并且不必专门测试可能为空的目录。
其变体/bin/sh
不关心隐藏名称:
#!/bin/sh
walk_dir () {
for pathname in "$1"/*; do
if [ -d "$pathname" ]; then
walk_dir "$pathname"
elif [ -e "$pathname" ]; then
case "$pathname" in
*.txt|*.doc)
printf '%s\n' "$pathname"
esac
fi
done
}
DOWNLOADING_DIR=/Users/richard/Downloads
walk_dir "$DOWNLOADING_DIR"
使用中的globstar
和exglob
shell 选项bash
,甚至可以执行以下操作(无需递归)来移动文件:
shopt -s globstar extglob
mv "$DOWNLOADING_DIR"/**/*.@(txt|doc) "$destdir"
...除非结果文件列表太长。匹配**
路径名中的斜杠(由 启用globstar
),并*.@(txt|doc)
匹配以 或 结尾的任何文件名.txt
(.doc
由 启用extglob
)。
一种更高效、更便携的方法,可以在某个顶级目录中或下查找文件名后缀为 或 的常规文件.txt
,并将它们移动到其他目录:.doc
$topdir
$destdir
find "$topdir" -type f \( -name '*.txt' -o -name '*.doc' \) \
-exec mv {} "$destdir" \;
使用 GNUmv
你可以让它变得更有效率,
find "$topdir" -type f \( -name '*.txt' -o -name '*.doc' \) \
-exec mv -t "$destdir" {} +
这种变化会移动批次文件而不是一次一个文件。使用mv
with-v
来查看移动的内容,或者添加-print
before来获取调用的-exec
路径名列表。mv