bash . 移动文件(带有指定后缀的文件除外)

bash . 移动文件(带有指定后缀的文件除外)

在 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

如果您使用findgrepxargs,您可以相当轻松地做到这一点。

我确信有更好的结构,但我马上想到的是这个:

# 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 \

相关内容