成对处理文件
Process files in pairs
我有一个文件列表:
file_name_FOO31101.txt
file_name_FOO31102.txt
file_name_FOO31103.txt
file_name_FOO31104.txt
我想使用成对的文件输入下游程序,例如:
program_call file_name_01.txt file_name_02.txt
program_call file_name_03.txt file_name_04.txt
...
我不想:
program_call file_name_02.txt file_name_03.txt
我需要按如下方式循环执行此操作:
#!/bin/bash
FILES=path/to/files
for file in $FILES/*.txt;
do
stem=$( basename "${file}" ) # stem : file_name_FOO31104_info.txt
output_base=$( echo $stem | cut -d'_' -f 1,2,3 ) # output_base : FOO31104_info.txt
id=$( echo $stem | cut -d'_' -f 3 ) # get the first field : FOO31104
number=$( echo -n $id | tail -c 2 ) # get the last two digits : 04
echo $id $((id+1))
done
但这并没有产生我想要的结果。
在每个循环中我想调用一个程序一次,输入两个文件(第一个文件的最后 2 位总是奇数 01
,第二个文件的最后 2 位总是偶数 02
)
我实际上根本不会使用 for
循环。 while
关闭 shift
s 文件的循环是执行此操作的完全合理的方法。
# here, we're overriding the argument list with the list of files
# ...you can do this in a function if you want to keep the global argument list intact
set -- "$FILES"/*.txt ## without these quotes paths with spaces break
# handle the case where no files were found matching our glob
[[ -e || -L ]] || { echo "No .txt found in $FILES" >&2; exit 1; }
# here, we're doing our own loop over those arguments
while (( "$#" > 1 )); do ## continue in the loop only w/ 2-or-more remaining
echo "Processing files and " ## ...substitute your own logic here...
shift 2 || break ## break even if test doesn't handle this case
done
# ...and add your own handling for the case where there's an odd number of files.
(( "$#" )) && echo "Left over file still exists"
请注意,$#
在这里 (( )) 内被引用是为了 Whosebug 的语法突出显示,而不是因为它们需要这样做。 :)
顺便说一下——考虑使用 bash 的原生字符串操作。
stem=${file##*/}
IFS=_ read -r p1 p2 id p_rest <<<"$stem"
number=${id:$(( ${#id} - 2 ))}
output_base="${p1}${p2}${id}"
echo "$id $((10#number + 1))" # 10# ensures interpretation as decimal, not octal
我有一个文件列表:
file_name_FOO31101.txt
file_name_FOO31102.txt
file_name_FOO31103.txt
file_name_FOO31104.txt
我想使用成对的文件输入下游程序,例如:
program_call file_name_01.txt file_name_02.txt
program_call file_name_03.txt file_name_04.txt
...
我不想:
program_call file_name_02.txt file_name_03.txt
我需要按如下方式循环执行此操作:
#!/bin/bash
FILES=path/to/files
for file in $FILES/*.txt;
do
stem=$( basename "${file}" ) # stem : file_name_FOO31104_info.txt
output_base=$( echo $stem | cut -d'_' -f 1,2,3 ) # output_base : FOO31104_info.txt
id=$( echo $stem | cut -d'_' -f 3 ) # get the first field : FOO31104
number=$( echo -n $id | tail -c 2 ) # get the last two digits : 04
echo $id $((id+1))
done
但这并没有产生我想要的结果。
在每个循环中我想调用一个程序一次,输入两个文件(第一个文件的最后 2 位总是奇数 01
,第二个文件的最后 2 位总是偶数 02
)
我实际上根本不会使用 for
循环。 while
关闭 shift
s 文件的循环是执行此操作的完全合理的方法。
# here, we're overriding the argument list with the list of files
# ...you can do this in a function if you want to keep the global argument list intact
set -- "$FILES"/*.txt ## without these quotes paths with spaces break
# handle the case where no files were found matching our glob
[[ -e || -L ]] || { echo "No .txt found in $FILES" >&2; exit 1; }
# here, we're doing our own loop over those arguments
while (( "$#" > 1 )); do ## continue in the loop only w/ 2-or-more remaining
echo "Processing files and " ## ...substitute your own logic here...
shift 2 || break ## break even if test doesn't handle this case
done
# ...and add your own handling for the case where there's an odd number of files.
(( "$#" )) && echo "Left over file still exists"
请注意,$#
在这里 (( )) 内被引用是为了 Whosebug 的语法突出显示,而不是因为它们需要这样做。 :)
顺便说一下——考虑使用 bash 的原生字符串操作。
stem=${file##*/}
IFS=_ read -r p1 p2 id p_rest <<<"$stem"
number=${id:$(( ${#id} - 2 ))}
output_base="${p1}${p2}${id}"
echo "$id $((10#number + 1))" # 10# ensures interpretation as decimal, not octal