我的工作目录中有一系列 markdown 文件:
$ ls *.md
csv_reader.md egrep.md find.md found_pdfs.md osPathSep_help.md readme.md smtplib_help.md today.md
我想删除它们,除了“today.md”
#!/usr/local/bin/bash
for i in ./*.md ; do
if [[ $i != "today.md" ]]; then
echo $i
fi
done
运行它并得到
$ bash bash/remove_files.sh
./csv_reader.md
./egrep.md
./find.md
./found_pdfs.md
./osPathSep_help.md
./readme.md
./smtplib_help.md
./today.md
尽管如此,结构化命令在命令行中并不方便,我如何用更短的命令完成这样的任务
答案1
使用否定匹配(需要shopt -s extglob
,但可能已经设置):
rm !(today).md
(可以先使用ls
而不是rm
检查结果)。
强大的力量extglob
,你也可以做
rm !(yesterday|today).md
如果你想保留两个文件。
答案2
find . -maxdepth 1 -name '*.md' ! -name today.md -type f -print
-type f
应该只找到当前目录中的所有文件( )(.
或者明确地在其中放置一个目录名称)(-maxdepth 1
防止以下子目录.md
) 以( )结尾-name '*.md'
,不包括 ( !
) 文件today.md
。
请务必包含单引号,'*.md'
这样您的 shell 在执行之前就不会尝试将其扩展到当前目录中的 .md 文件列表find
。
它将打印要删除的文件列表。改为-print
删除-delete
它们。
答案3
以上是更好的解决方案,但您的代码无法工作的原因是由于比较。
“./today.md”不等于“today.md”。
答案4
Unix 因具有多种方法来完成相同的简单任务而闻名。有些人喜欢使用sed
,但我喜欢grep
,所以如果我只是在命令行上输入,我会使用:
rm -i `ls *.md | grep -v '^today.md$'`
ls *.md
列出所有名称以.md
.|
将结果通过管道传输ls
到下一个命令,但作为副作用,会导致ls
在多行上列出文件,每行 1 个。grep -v '^today.md$'
回显不完全匹配的行today.md
rm -i
然后获取结果(因为命令在反引号内),询问您是否要一一删除它们。当我使用生成的文件列表时,我总是这样做,以防生成器出现问题。您可以在不询问的rm
情况下使用-i
来删除文件,但这风险更大,而且也不会为您提供已删除文件的列表。