Bash脚本:一元运算符预期错误?

时间:2014-07-11 01:14:34

标签: bash

#!/usr/bin/env bash

FILETYPES=( "*.html" "*.css" "*.js" "*.xml" "*.json" )
DIRECTORIES=`pwd`
MIN_SIZE=1024

for currentdir in $DIRECTORIES
do
   for i in "${FILETYPES[@]}"
   do
      find $currentdir -iname "$i" -exec bash -c 'PLAINFILE={};GZIPPEDFILE={}.gz; \
         if [ -e $GZIPPEDFILE ]; \
         then if [ `stat --printf=%Y $PLAINFILE` -gt `stat --printf=%Y $GZIPPEDFILE` ]; \
                then    gzip -k -4 -f -c $PLAINFILE > $GZIPPEDFILE; \
                 fi; \
         elif [ `stat --printf=%s $PLAINFILE` -gt $MIN_SIZE ]; \
            then gzip -k -4 -c $PLAINFILE > $GZIPPEDFILE; \
         fi' \;
  done
done

此脚本使用gzip压缩所有Web静态文件。当我尝试运行它时,我收到此错误bash: line 5: [: 93107: unary operator expected。这个脚本出了什么问题?

2 个答案:

答案 0 :(得分:3)

您需要导出MIN_SIZE变量。你有find spawn的bash没有它的值,所以脚本运行(正如我在@ ooga的回答中提到的那样)[ $result_from_stat -gt ]这是一个错误(当结果时)是93107)获取[ 93107 -gt ]哪个(如果你在shell中运行)获得输出:

$ [ 93107 -gt ]
-bash: [: 93107: unary operator expected

答案 1 :(得分:2)

这可能更简单:

#!/usr/bin/env bash

FILETYPES=(html css js xml json)
DIRECTORIES=("$PWD")
MIN_SIZE=1024

IFS='|' eval 'FILTER="^.*[.](${FILETYPES[*]})\$"'

for DIR in "${DIRECTORIES[@]}"; do
    while IFS= read -ru 4 FILE; do
        GZ_FILE=$FILE.gz
        if [[ -e $GZ_FILE ]]; then
            [[ $GZ_FILE -ot "$FILE" ]] && gzip -k -4 -c "$FILE" > "$GZ_FILE"
        elif [[ $(exec stat -c '%s' "$FILE") -ge MIN_SIZE ]]; then
            gzip -k -4 -c "$FILE" > "$GZ_FILE"
        fi
    done 4< <(exec find "$DIR" -mindepth 1 -type f -regextype egrep -iregex "$FILTER")
done
  • 无需使用pwd。你可以$PWD。也许你需要的是一个数组变量。
  • 不是使用静态字符串命令多次调用bash作为find的参数,而是通过进程替换从pipe或更好地从已命名的pipe读取输入。
  • 您可以使用-ot-nt
  • ,而不是比较统计信息
  • 如果您通过重定向(-f)编写输出,则不需要>,因为默认情况下该重定向形式会覆盖目标。
  • 您可以通过制作一个模式来对多个文件调用find,因为它更有效。您可以查看我如何制作过滤器并使用-iregex。可能适用\( -iname one_ext_pat -or -iname another_ext_pat \)也可以适用,但更难。
  • exec是可选的,以防止不必要地使用其他进程。
  • 始终更喜欢[[ ]]而不是[ ]
  • 4<打开包含文件描述符4的输入,-u 4从该文件描述符中读取read,而不是stdin (0)
  • 您可能需要的是-ge MIN_SIZE(大于或等于)-gt

考虑一下,如果您的bash是4.0或更高版本,readarray是一个更干净的选项:

for DIR in "${DIRECTORIES[@]}"; do
    readarray -t FILES < <(exec find "$DIR" -mindepth 1 -type f -regextype egrep -iregex "$FILTER")
    for FILE in "${FILES[@]}"; do
        ...
    done
done