执行此存档脚本时出现“gzip: invalid option -- 'x'”错误

执行此存档脚本时出现“gzip: invalid option -- 'x'”错误

该脚本用于压缩并归档给定目录中任何大于 20 MB 的文件:

#!/bin/bash

#Variables
BASE=/home/sengh/scripts
DEPTH=1 #how deep to go in the find operation
RUN=0

#Check if the directory is present or not
if [ ! -d $BASE ]
then
    echo "directory does not exist: $BASE"
    exit 1
fi

#Create 'archive' folder if not present
if [ ! -d $BASE/archive ]
then
    mkdir $BASE/archive
fi

#Find the list of files larger than 20 MB
for i in 'find $BASE -maxdepth $DEPTH -type f -size +20M'
do
    if [ $RUN -eq 0 ]
    then
        echo "[$(date "+%Y-%m-%d %H:%M:%S")] archiving $i ==> $BASE/archive"
        gzip $i || exit 1
        mv $i.gz $BASE/archive || exit 1
    fi
done

我得到以下输出:

[2024-01-26 23:55:06] 归档查找 $BASE -maxdepth $DEPTH -type f -size +20M ==> /home/sengh/scripts/archive gzip: 无效选项 -- 'x' 尝试 `gzip --help' 获取更多信息。

我尝试浏览 gzip 的手册页,但没有帮助,因为我没有使用“x”这样的选项。请帮忙。

答案1

使用以下方法更容易zsh

#! /bin/zsh --
mkdir -p -- ~/scripts/archive || exit

PROMPT4='[%D{%F %T}] ' # for the xtrace output to be prefixed by the
                       # current time in [%F %T] strftime format

set -o xtrace -o noclobber # xtrace provides a trace of each command
                           # being executed. noclobber prevents
                           # redirection clobbering files.
for file (~/scripts/*(ND.LM+20))
  gzip -c -- $file > ~/archive/scripts/$file.gz && rm -f -- $file || exit

(ND.LM+20)部分是全局限定符,这进一步限定了全局扩展:

  • N仅适用nullglob于该一个 glob,以便该 glob 扩展为空,而不是在没有匹配项时返回错误。您通常希望在 for 循环列表中使用它。
  • D仅适用dotglob于该一个 glob 来包含隐藏文件(就像find默认情况下一样)
  • LM+20相当于 GNUfind-size +20M限制扩展为大小舍入为整数兆字节且严格大于 20 的文件,即 20971521 字节L或更长的文件。
  • .喜欢-type f是限制于常规的文件仅排除任何其他类型的文件,例如符号链接、fifos、目录、设备...

使用 bash 以相同的可靠性级别执行相同的操作相当麻烦,并且需要最新版本的 GNU 实用程序。

#! /bin/bash --
mkdir -p -- ~/scripts/archive || exit

PS4='[\D{%F %T}] ' # for the xtrace output to be prefixed by the
                   # current time in [%F %T] strftime format

set -o noclobber # prevents redirection clobbering files.

while IFS= read -rd '' -u3 file; do
  (set -o xtrace
    gzip -c -- "$file" > ~/archive/scripts/"$file".gz) &&
      rm -f -- "$file"
  ) 3<&- || exit
done 3< <(
  find -H -files0-from <(printf '%s\0' ~/scripts/archive) \
    -mindepth 1 -maxdepth 1 -type f -size +20M -print0 |
    sort -z
)

一如既往,你需要--将选项与非选项参数分开确保那些以 . 开头的非选项参数不会被视为选项-。然而,对于find,这并没有帮助,因为即使在 之后,如果它们以(或者是, , )--开头,它们仍然被视为谓词。对于 BSD ,只需使用 代替,但 GNU不支持这一点。然而从 4.9 版本开始,它支持从文件传递文件列表。-()!findfind -f "$dir"find -- "$dir"find-f-files0-from

关于您的代码的一些注释:

  • 在 bash 中,参数扩展必须加引号,否则它们会经历 split+glob。看什么时候需要双引号?以及有关该主题的许多其他问答。 shellcheck 还可以帮助您发现这种初学者错误。
  • '...'用于强引用。'find ...'是文字字符串find ...。但即使您用反引号 ( `...`) 替换这些单引号,这仍然是错误的方法。看为什么循环查找的输出是不好的做法?了解详情。
  • 最好避免做像if condition-not-met; then do-something-that-would-make-sure-the-condition-is-met; fi你这样的事情,因为它介绍了if [ ! -d ...]; then mkdir...TOCTOU 比赛条件。使用 时-pmkdir仅当目录(以及所有前导目录组件)不存在时才创建该目录,并且仅当目录返回后不存在时才会失败。

在这里,第一点和第二点的组合导致gzip返回该错误。

该循环正在循环遍历一个值,即find $BASE -maxdepth...。由于您忘记引用$i,gzip $i受到$isplit+glob 的影响,并且默认值$IFS,gzip被传递find, $BASE,-maxdepth...的内容中的单独参数$i作为一个参数。

GNU 实用程序有一个错误特征,即使在非选项参数之后,选项仍然可以被识别(这使得不要忘记那些分隔符变得更加重要--),因此-maxdepth被视为 的选项gzip,并且被视为组合在一起的单字母选项,因此相同作为-m -a -x -d...

-m是一个当前未记录的选项,告诉gzip/gunzip不保留修改时间,-a,在类 Unix 系统上也未记录,缩写--ascii仅与 Microsoft Windows 相关(并且其名称相当具有误导性),-x不在受支持的选项之列,甚至没有记录的,所以你会得到这个错误。

相关内容