Bash脚本调用外部脚本时循环迭代跳过问题排查求助
Bash循环调用脚本时部分迭代未执行的问题解决
问题描述
我编写了一个Bash脚本,从CSV文件第一列读取参数并循环调用testing.sh脚本,但部分循环迭代未执行:仅在循环内打印element时能输出所有项,一旦执行testing.sh,对应的echo语句就不再打印,推测问题与调用testing.sh的方式有关。
主脚本代码:
code_sections_file="code_sections.csv" script="testing.sh" pwd awk -F "," '{print $1}' "$code_sections_file" | while IFS= read -r element; do echo "======= $element ========" ./testing.sh "$element" done
testing.sh脚本代码:
#!/bin/bash file_non_compile=() #============================== CSV Structure ==================================== # Bug Name, Example Name, Example Path, Starting Line, Ending Line #================================================================================= code_sections_file="code_sections.csv" # ---------------------------- Preprocessing input ------------------------------- result="$1" result_line=$(grep "^$result," "$code_sections_file") IFS="," read -ra info_array <<< $result_line bug="${info_array[0]}" example_name="${info_array[1]}" example_path="${info_array[2]}" first_line="${info_array[3]}" second_line="${info_array[4]}" # ------------------------------ Directory Paths ---------------------------------- error_path="../testlogs/noncompiled/$bug" code_folder="nvml/src/examples/libpmemobj/$example_path" # nvml/src/examples/libpmemobj/$example_path - Path to the file original_folder="../original/$example_path" # ../original/$example_path - Path to the original state of the file buged_folder="../buged/$example_path" # ../buged/$example_path - Path to the bugged state of the file patch_path="./patch/$example_name/$bug.patch" # ./patch/$example_path{-.c+patch} - file with the buggy patch IFS='/' read -ra patharr <<< "$example_path" testlogs_path="../testlogs/${patharr[0]}/$bug" # ../testlogs/$example_path.split("/")[0]/$bug_(prompt_eng_tech).txt - file with logs results="../masterThesis/Results" # ../masterThesis/Results/{prompt}/{$bug.txt} echo "$patch_path" echo "$bug $example_name $example_path $first_line $second_line" # ================================================================================== # Copy original code file to a folder cp $code_folder $original_folder sleep 10 # ===================================== Bug ======================================== echo "=========== $bug =============" sleep 5 # Apply the patch bug echo "Applying the bug patch..." ./patch/patch.sh ./ $patch_path sleep 2 # Copy buggy file to a folder cp $code_folder $buged_folder echo "Done." sleep 10 # Build the examples echo "Compiling the code..." make nvml-example &> /dev/null if [ $? -ne 0 ]; then echo " ========== Make failed =============== " file_non_compile+(" ") read fi echo "Done." sleep 4 # Execute program and save log to file. echo "Executing the buggy program..." sudo make nvml-exec arg=$example_name > ../testlogs/$example_name/$bug.txt echo "Done. Output saved to ../testlogs/$example_name/$bug.txt" sleep 2 # ====================================================================================== verify_correction() { current_strategy=$1 echo $current_strategy echo "Writing bug correction..." prev_line=$((first_line - 1)) sed "${first_line},${second_line}d" $code_folder > ../temp.txt && sed -n -e "/\`\`\` \?C/,/\`\`\`/p" -e "/''' \?C/,/'''/p" $results/$current_strategy/$bug.txt | sed '1d;$d' | sed "${prev_line}r /dev/stdin" ../temp.txt > ../temp2.txt && mv ../temp2.txt ../temp.txt #sed '180,239d' nvml/src/examples/libpmemobj/hashmap/hashmap_tx.c > ../temp.txt && sed '4,57!d' ../mastersThesis/Results/ZeroShot/hashmap_tx_backup_3.txt | sed '179r /dev/stdin' ../temp.txt > ../temp2.txt && mv ../temp2.txt ../temp.txt # Write temp file content to original file cp ../temp.txt $code_folder echo "Done." # Rebuild Examples echo "Compiling code..." make nvml-example &> /dev/null if [ $? -ne 0 ]; then echo " ========== Make failed =============== " file_non_compile+("$bug\_$1") read fi echo "Done." sleep 4 # Execute "repaired" program and save to logs echo "Executing program with Zero-Shot correction..." sudo make nvml-exec arg=$example_name > ../testlogs/$example_name/$bug\_$2.txt echo "Done. Output saved to ../testlogs/$example_name/$bug\_$2.txt" # Return buggy code echo "Reverting to buggy code and recompiling..." cp ../buged/$example_path $code_folder make nvml-example &> /dev/null echo "Done." sleep 2 } # ================================= Zero-Shot Learning ================================= verify_correction "ZeroShot" "Zero" verify_correction "ZeroShotCoT" "ZeroCoT" verify_correction "MoreExamples/FewShot" "Two" verify_correction "MoreExamples/FewShotCoT" "TwoCoT" verify_correction "OneExample/FewShot" "One" verify_correction "OneExample/FewShotCoT" "OneCoT" echo "Reset code sample..." ./patch/patch.sh -R ./ $patch_path sleep 2 echo "Done." echo "The following corrections did not compile:" if [ ${#file_non_compile[@]} -gt 0 ]; then for file in "${file_non_compile[@]}"; do echo "$file" >> "$error_path" done fi echo "All verifications done for bug $bug." echo "Results can be found in ../testlogs/$example_name/ folder."
问题原因
核心问题是管道的标准输入被testing.sh中的read命令消耗。外层循环通过awk ... | while read ...的管道方式获取输入,管道的stdin会被循环内执行的testing.sh共享。而testing.sh里有多处单独的read命令(比如编译失败时的暂停操作),这些命令会读取管道中剩余的内容,导致外层while read提前结束,后续迭代无法执行。
解决方案
方案1:修改testing.sh中的read命令
testing.sh里的read只是用来暂停脚本,不需要读取管道内容。将所有单独的read替换为:
# 读取一个字符但不从stdin获取,避免消耗管道内容 read -n 1 < /dev/null # 或者直接用sleep替代(如果不需要等待用户按键) # sleep 5
方案2:重构外层循环,避免使用管道
用进程替换替代管道,让while read的stdin独立于子进程:
code_sections_file="code_sections.csv" script="testing.sh" pwd while IFS= read -r element; do echo "======= $element ========" ./testing.sh "$element" done < <(awk -F "," '{print $1}' "$code_sections_file")
方案3:使用临时文件存储awk输出
先把awk的结果写入临时文件,再循环读取:
code_sections_file="code_sections.csv" script="testing.sh" pwd tmpfile=$(mktemp) awk -F "," '{print $1}' "$code_sections_file" > "$tmpfile" while IFS= read -r element; do echo "======= $element ========" ./testing.sh "$element" done < "$tmpfile" rm "$tmpfile"
内容的提问来源于stack exchange,提问作者Martim Afonso
相关产品推荐
相关产品推荐

