用于循环逻辑跳过处理文件

用于循环逻辑跳过处理文件

我编写了以下脚本,尝试实现自动化,对我处理的文本文件集进行一些常见的转换:

#!/bin/bash
set -e

if [ $# -eq 0 ]; then
echo "USAGE: $0 FILE"
echo "USAGE: Pass a colon-delimited text file as input."
exit
else               
    for i; do
      echo "Checking file \"$i\" is colon-delimited..." &&
        head "$i" | while IFS= read -r line; do 
        if [[ " $line " =~ ':' ]]; then continue;
        else 
            echo "Input \"$i\" is not colon-delimited. Leaving file."
            continue 2
        fi
        done        

        echo "Transforming file \"$i\"..." &&
        awk -F: '$1!="" && $2!=""' "$i" |                 # Filter out lines with empty columns
        awk -F: '{gsub(/ /, "", $1); print $1 FS $2}' |   # Remove all spaces in first column; assumes two columns delimited by ':'
        grep -aE ":|@" |                                  # Filter out lines that don't contain '@' or ':'
        tr -d '\000-\011\013-\037' |                      # Remove all control characters apart from (Linux) newline
        awk 'length >=7 && length <=150' |                # Filter out very short and long lines
        LC_ALL=C sort -u > "${i%_final.*}" #&&            # Sort and deduplicate
    done
fi  

预期行为

将文件作为输入,如果未给出输入则退出。读取每个输入文件的前 10 行以检查它是否包含冒号。如果包含,则将转换应用于文件;如果其中一行不包含冒号,则跳过该文件并开始处理下一个文件。

实际行为

大部分脚本均可正常工作;如果没有输入,脚本就会退出,并成功确定文件是否以冒号分隔。

问题仅限于for循环:无论我尝试多少种变化breakcontinue它们最终都会以相同的结果结束 - 所有文件都会被转换,无论它们是否以冒号分隔。

运行脚本bash -n壳牌检测没有显示任何问题。

所有这些都指向一个非常简单的逻辑问题,但我已经研究了好几天,仍然无法将我的逻辑表达成代码。

这是我运行命令时得到的输出:

$ time ../transform_files.sh *
Checking file "file1" is colon-delimited...
Transforming file "file1"...
awk: cmd. line:1: (FILENAME=- FNR=4) warning: Invalid multibyte data detected. There may be a mismatch between your data and your locale.
Checking file "file2.sh" is colon-delimited...
Input "file2.sh" is not colon-delimited. Leaving file.
Transforming file "file2.sh"...
Checking file "file3.in.txt" is colon-delimited...
Transforming file "file3.in.txt"...
awk: cmd. line:1: (FILENAME=- FNR=44) warning: Invalid multibyte data detected. There may be a mismatch between your data and your locale.
Checking file "file4.txt" is colon-delimited...
Input "file4.txt" is not colon-delimited. Leaving file.
Transforming file "file4.txt"...

real    0m4.375s
user    0m0.349s
sys     0m0.805s

注意:我知道awk可以使用 修复错误LC_ALL=C,但我的输入文件往往包含大量无法丢弃的非 ASCII 字符。

答案1

我认为逻辑本身还不错。问题是continue只能影响执行它的 shell 的流程。

Bash 在子 shell 上下文中运行管道的右侧。代码的相关片段是管道;continue 2位于子 shell 中:

head "$i" | while …
   continue 2
done

for这就是为什么它不能影响你的循环流程外部子壳。

人们通常在以下情况下发现 Bash 的这种行为read“不起作用”。对你来说,这是continue 2“不起作用”的,但原因是一样的。解决方案也是如此:

  • while …不在管道中运行:

     while … done < <(head "$i")
    
  • 或者告诉 Bash 改变其行为。告诉它在当前 shell 环境中运行管道的最后一个命令:

     # before the troublesome pipeline
     shopt -s lastpipe
    

相关内容