在 bash 中是否有任何方法可以遍历不以特定后缀结尾的文件?
例如我正在这样做:
mv $INCDIR/HDR_10_* $BACKUPDIR
但我不想移动以 .gz 结尾的 HDR_10_*
答案1
这对于文件移动有效:
mv $( echo $INCDIR/HDR_10_* | grep -v '\.gz$') $BACKUPDIR
您还询问“将不以特定后缀结尾的文件全部匹配?” Bash 有 shell 选项 (shopt) extglob,它允许扩展的匹配语法。!(...glob...)
匹配所有内容但全局模式。
shopt -s extglob
cd $INCDIR
mv !(*.gz) $BACKUPDIR
会工作仅有的如果 $INCDIR 仅包含名为 HDR_10_* 的文件,具体来说,它将匹配 $INCDIR 中与 *.gz 不匹配的任何文件或目录。从技术上讲,您要求的是一个同时匹配一个模式但不匹配另一个模式的 glob,我认为这不是一个简单的单一实体。
答案2
在 ksh 下,!(*.gz)
匹配当前目录中除匹配 的文件之外的所有文件*.gz
。在 bash 中,在 之后可以使用相同的模式shopt -s extglob
,在 zsh 中,在 之后可以使用相同的模式setopt ksh_glob
。ksh 和 bash 都没有办法取正匹配和负匹配的交集。在 zsh 中,在 之后setopt extended_glob
,您可以写入$INCDIR/HDR_10_*~$INCDIR/*.gz
。
在任何 Bourne 风格的 shell(ash、bash、ksh、zsh 等)中,一种解决方案是遍历文件并检查每个匹配项。
for x in "$INCDIR"/HDR_10_*; do
case "$x" in
*.gz) :;;
*) mv -- "$x" "$BACKUPDIR";;
esac
done
另一个解决方案是使用find
。以下命令也将移动子目录中的文件。
find "$INCDIR" -type f -name 'HDR_10_*' \! -name '*.gz' -exec mv {} "$BACKUPDIR" \;
如果你有 GNU find (例如在 Linux 下),你可以-maxdepth 1
在之后添加"$INCDIR"
以直接在 中移动文件$INCDIR
。
注意您应该始终使用双引号括住变量替换(例如"$INCDIR"
,不是$INCDIR
)除非您有充分的理由省略它们。否则,如果您的文件名称中包含空格或 等特殊字符,您将遇到麻烦\[?*
。
答案3
如果您使用find
、grep
和xargs
,您可以相当轻松地做到这一点。
我确信有更好的结构,但我马上想到的是这个:
# find <here>| <pattern> | <notpattern>| <what to do>
find $INCDIR | grep HDR_10_ | grep -v .gz | xargs mv $BACKUPDIR
评论中指出了一个修正,上面的快速刺杀由于mv
没有按正确的顺序获取其参数而不起作用xargs
:
find $INCDIR -name 'HDR_10_*' ! -name '*.gz' -exec mv {} $BACKUPDIR \