首页 > 解决方案 > bash:读取命令在循环中被忽略

问题描述

我正在使用一些代码来检查某些文件是否相互匹配,然后向用户提示问题并根据用户响应采取适当的措施。但是,bash 完全忽略了我的读取命令!

declare -i int
int=1
find ./1 -name '*.xyz' | while read FILENAME
do
find . -name '*.xyz' | while read FILENAME2
do
    if [ $FILENAME != $FILENAME2 ]; then
        if [ $(dirname "${FILENAME}") != $(dirname "${FILENAME2}") ]; then
            if [ $(basename "${FILENAME}") == $(basename "${FILENAME2}") ]; then
                int=int+1
                if cmp -s "$FILENAME" "$FILENAME2" ; then
                    echo "Match", "$FILENAME", "$FILENAME2", "$int"
                else
                    # echo "No Match", "$FILENAME", "$FILENAME2", "$int"
                    read -p "No match modify? (y/n)" d
                    echo "$d ";
                fi
                if [ "$int" -gt 44 ]; then
                    exit 1
                fi
            fi
        fi
    fi
done
done 

我正在使用 osx。我已经检查并且一个简单的读取命令在我的终端(iterm)的循环之外正常运行。

标签: bashmacos

解决方案


整个while循环的标准输入被重定向。Any将消耗来自而不是来自用户终端read的输入的一行。find

find无论如何,在外循环内重复运行相同的命令效率非常低。可能将两个命令的结果收集find到两个数组中,然后简单地循环内存中的字符串,而不是一遍又一遍地在相同的目录上旋转磁盘。

但是,如果您尝试在外部查找1与内部1同名文件相同的文件,则更有效的方法是运行

find . -name '*.xyz' -exec shasum {} +

然后在一个简单的 Awk 脚本中处理结果输出。也许是这样的:

#!/bin/bash

find . -name '*.xyz' -exec shasum {} + |
# Reverse each line, sort by first field, reverse again
# Entries for files with the same basename will now be adjacent
rev | sort -t / -k1,1 | rev |
awk -F / '$NF!=p { p=$NF; delete a; c=""; }
    { split($0, x, /[ \t]+/);
        if(x[2] ~ /^\.\/1\//) { 
            if (a[x[1]]) print a[x[1]];
        c = x[1];
            next
        }
        if (c) {
            if (x[1] == c) print x[2];
            next;
        }
        a[x[1]] = x[2] (a[x[1]] ? ORS a[x[1]] : ""); }'

推荐阅读