You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Bash与Csh循环仅最后一次迭代生效?求解决方法

问题排查与解决:Shell脚本循环仅最后一次迭代生效

问题现象

  • 编写Bash/Csh脚本遍历CSV中的字符串,搜索对应文件路径并写入输出文件,但仅最后一次循环生效
  • 单独执行echo $str时内容符合预期,但echo完整find命令时,前几次迭代输出异常(仅显示后半段),只有最后一次能输出完整命令

用户提供的脚本如下:

Bash脚本

#!/bin/bash

#CSV file containing the list of strings to search for
strings_file="/project/crism/users/phillms1/Murchie2017MDAP/tyrrhena_tile_ids.csv"

#Output file where the full path of the file containing the strings will be appended
output_file="/project/crism/users/phillms1/Murchie2017MDAP/tyrrhena_tile_id_paths.txt"

#Read the strings from the CSV file
strings=$(cat "$strings_file")

#Search the current directory and all subdirectories for files containing the strings and "MRRSU" in their filename
for str in $strings; do
find . -type f -name "*$str*MRRSU*.IMG" -exec readlink -f {} ; >> "$output_file"
done

Csh脚本

#!/bin/csh

# CSV file containing the list of strings to search for
set strings_file = "/project/crism/users/phillms1/Murchie2017MDAP/tyrrhena_tile_ids.csv"

# Output file where the full path of the file containing the strings will be appended
set output_file = "/project/crism/users/phillms1/Murchie2017MDAP/tyrrhena_tile_id_paths.txt"

# Read the strings from the CSV file
set strings = `cat $strings_file`

# Search the current directory and all subdirectories for files containing the strings and "MRRSU" in their filename
foreach str ($strings)
  find . -type f -name "*$str*MRRSU*.IMG" -exec readlink -f {} \; >> $output_file
  #set files = `find . -type f -name "*$str*MRRSU*.IMG" -exec readlink -f {} \;`
  #echo $files >> $output_file
end

#foreach str ($strings)
#  set files = `find . -type f -name "*$str*MRRSU*.IMG"`
#  if ($#files >= 0) then
#    foreach file ($files)
#      set full_path = `readlink -f $file`
#      echo $full_path >> $output_file
#    end
#  endif
#end

问题根源

你的CSV文件大概率带有Windows风格的换行符(\r\n),而非Unix系统默认的(\n)。当用cat读取文件时,每行末尾的\r(回车符)会被保留在字符串变量中(最后一行可能例外)。

当执行echo find . -type f -name "*$str*MRRSU*.IMG" ...时,$str末尾的\r会强制光标回到行首,后续内容会覆盖掉前面的find . -type f -name "*xxx部分,导致输出看起来不完整。同时,带\r的字符串无法匹配实际文件名(文件名不含回车符),所以前几次循环的find命令找不到文件,只有最后一行无\r的字符串能正常执行。

你可以用cat -A your_file.csv查看文件,若每行末尾有^M,则确认是Windows换行符问题。

解决方法

方法1:预处理CSV文件,转换换行符

直接将文件转换为Unix格式:

# 用dos2unix工具(多数系统自带)
dos2unix /project/crism/users/phillms1/Murchie2017MDAP/tyrrhena_tile_ids.csv

# 若无dos2unix,用sed替代
sed -i 's/\r$//' /project/crism/users/phillms1/Murchie2017MDAP/tyrrhena_tile_ids.csv

方法2:修改脚本,读取时过滤回车符

Bash脚本优化(逐行读取更可靠)

#!/bin/bash

strings_file="/project/crism/users/phillms1/Murchie2017MDAP/tyrrhena_tile_ids.csv"
output_file="/project/crism/users/phillms1/Murchie2017MDAP/tyrrhena_tile_id_paths.txt"

# 逐行读取并过滤回车符,跳过空行
while IFS= read -r str; do
    str=$(echo "$str" | tr -d '\r')
    [ -z "$str" ] && continue
    find . -type f -name "*$str*MRRSU*.IMG" -exec readlink -f {} \; >> "$output_file"
done < "$strings_file"

Csh脚本优化

#!/bin/csh

set strings_file = "/project/crism/users/phillms1/Murchie2017MDAP/tyrrhena_tile_ids.csv"
set output_file = "/project/crism/users/phillms1/Murchie2017MDAP/tyrrhena_tile_id_paths.txt"

# 读取时直接过滤回车符,跳过空行
foreach str (`cat $strings_file | tr -d '\r'`)
    if ($str == "") continue
    find . -type f -name "*$str*MRRSU*.IMG" -exec readlink -f {} \; >> $output_file
end

额外提示

  • 尽量避免用cat直接赋值给变量后遍历,逐行读取的方式能更好处理空行、特殊字符等边界情况
  • 若CSV文件中有空格或特殊字符,建议用更严谨的读取方式(比如Bash中用IFS=$'\n'限定换行符分隔)

内容的提问来源于stack exchange,提问作者Michael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 16:20:38