Answers:
在bash,那么你可以通过启用做extglob
选择,就像这样(替换ls
用cp
,并添加目标目录,当然)
~/foobar> shopt extglob
extglob off
~/foobar> ls
abar afoo bbar bfoo
~/foobar> ls !(b*)
-bash: !: event not found
~/foobar> shopt -s extglob # Enables extglob
~/foobar> ls !(b*)
abar afoo
~/foobar> ls !(a*)
bbar bfoo
~/foobar> ls !(*foo)
abar bbar
您可以稍后使用禁用extglob
shopt -u extglob
f
,除foo
?
该extglob
外壳选项可以让你在命令行更强大的模式匹配。
您可以使用打开它shopt -s extglob
,然后使用关闭它shopt -u extglob
。
在您的示例中,您最初将执行以下操作:
$ shopt -s extglob
$ cp !(*Music*) /target_directory
全部可用分机结束水珠兵运营商(摘自man bash
):
如果使用shopt内置功能启用了extglob shell选项,则会识别出几个扩展模式匹配运算符。模式列表是由|分隔的一个或多个模式的列表。 可以使用以下一个或多个子图案来形成复合图案:
- ?(模式列表)
匹配给定模式的零个或一次- *(模式列表)
匹配给定模式的零个或多个出现- +(模式列表)
匹配给定模式的一个或多个出现- @(pattern-list)
匹配给定的模式之一- !(pattern-list)
匹配给定模式之一以外的任何内容
因此,例如,如果要列出当前目录中不是.c
或.h
文件的所有文件,则可以执行以下操作:
$ ls -d !(*@(.c|.h))
当然,正常的外壳球形化是可行的,因此最后一个示例也可以写成:
$ ls -d !(*.[ch])
.c
或.h
文件是目录。
D
内容,但不列出目录中可能包含的子目录的内容D
。
在bash中,的替代方法shopt -s extglob
是GLOBIGNORE
variable。并不是真的更好,但是我发现它更容易记住。
原始海报想要的示例可能是:
GLOBIGNORE="*techno*"; cp *Music* /only_good_music/
完成后,unset GLOBIGNORE
就可以rm *techno*
在源目录中了。
我个人的喜好是使用grep和while命令。这样一来,您就可以编写功能强大而又易读的脚本,以确保最终完成所需的操作。另外,通过使用echo命令,您可以在执行实际操作之前执行空运行。例如:
ls | grep -v "Music" | while read filename
do
echo $filename
done
将打印出最终将要复制的文件。如果列表正确,则下一步就是将复制命令替换为echo命令,如下所示:
ls | grep -v "Music" | while read filename
do
cp "$filename" /target_directory
done
bash
可以使用while IFS='' read -r filename
,但是换行符仍然是一个问题。通常,最好不要使用ls
枚举文件。这样的工具find
更适合。
for file in *; do case ${file} in (*Music*) ;; (*) cp "${file}" /target_directory ; echo ;; esac; done
我还没有看到这里还没有使用特技extglob
,find
或者grep
是处理两个文件列表作为集和“差异”他们使用comm
:
comm -23 <(ls) <(ls *Music*)
comm
比diff
它更可取,因为它没有多余的东西。
此返回组1中的所有元素,ls
即是不也在集2, ls *Music*
。这要求两个集合都必须排序才能正常工作。ls
和glob扩展没问题,但是如果您使用find
,请确保调用sort
。
comm -23 <(find . | sort) <(find . | grep -i '.jpg' | sort)
可能有用。
comm -23 <(ls) exclude_these.list
可以通过find找到一种解决方案。
$ mkdir foo bar
$ touch foo/a.txt foo/Music.txt
$ find foo -type f ! -name '*Music*' -exec cp {} bar \;
$ ls bar
a.txt
Find有很多选项,您可以非常明确地包含和排除哪些内容。
编辑:亚当在评论中指出,这是递归的。查找选项mindepth和maxdepth在控制此方面可能很有用。
find -maxdepth 1 -not -name '*Music*'
/ target_directory
以下作品列出了所有作品 *.txt
了当前目录文件,但以数字开头的文件除外。
这部作品在bash
,dash
,zsh
和所有其他POSIX兼容的炮弹。
for FILE in /some/dir/*.txt; do # for each *.txt file
case "${FILE##*/}" in # if file basename...
[0-9]*) continue ;; # starts with digit: skip
esac
## otherwise, do stuff with $FILE here
done
在第一行中,该模式/some/dir/*.txt
将导致for
循环遍历/some/dir
名称以结尾的所有文件.txt
。
在第二行中,使用case语句清除不需要的文件。–该${FILE##*/}
表达式从文件名(此处为/some/dir/
)中删除所有前导目录名组成部分,以便模式仅可与文件的基本名匹配。(如果仅根据后缀清除文件名,则可以将其缩短为$FILE
。)
在第三行中,将跳过所有与case
pattern [0-9]*
行匹配的文件(该continue
语句跳至for
循环的下一个迭代)。–如果愿意,您可以在此处做一些更有趣的事情,例如,使用来跳过所有不以字母(a–z)开头的文件[!a-z]*
,或者您可以使用多种模式来跳过几种文件名,例如[0-9]*|*.bak
,同时跳过两个.bak
文件以及不以数字开头的文件。
*.txt
而不是*
)。立即修复。
这样做会排除确切的“音乐”
cp -a ^'Music' /target
这个和那个排除音乐之类的东西?*或*?音乐
cp -a ^\*?'complete' /target
cp -a ^'complete'?\* /target
cp
在MacOS手册页中有一个-a
选项,但它确实完全不同的东西。哪个平台支持此功能?
ls /dir/*/!(base*)