2017-01-12 9 views
1

У меня есть список файлов:обрабатывать файлы в парах

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)

+2

Как и в сторону, все шапки имена переменных [задается POSIX] (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html) для использования переменных с значением, системы или оболочки, тогда как имена нижнего регистра зарезервированы для использования приложения. Подумайте об этом в своем собственном коде, чтобы предотвратить любую возможность топать по переменным со значением в системе по ошибке. (Эта спецификация является явной для переменных среды, но установка регулярной переменной оболочки заменяет любую переменную среды с похожим именем, поэтому они разделяют пространство имен). –

+2

BTW, '$ FILES/*. Txt' будут разбиты, если ваш путь' FILES' содержит пробелы, поэтому '' $ FILES "/ *. Txt'. –

+0

@CharlesDuffy - Спасибо - все это прекрасно знать – fugu

ответ

4

Я на самом деле не будет используйте петлю for. A 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 $1 || -L $1 ]] || { 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 $1 and $2" ## ...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 $1 still exists" 

Обратите внимание, что $# s приведены в (()) здесь подсветка синтаксиса StackOverflow, а не потому, что в противном случае они должны быть. :)


Кстати, рассмотрим использование встроенной струйной манипуляции 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 
+0

Обратите внимание, что этот подход работает даже с неприлично большими каталогами. – bishop

+0

Yup - это немного неочевидно, потому что нельзя передавать вектор аргументов (и набор переменных окружения) по определенному (зависящему от ОС) размеру в скрипт при его запуске, но вы все равно можете заменить его более крупным списком используя 'set' позже. –

+1

Обратите внимание, что 'shift 2' эквивалентен' shift; shift' - по крайней мере, в bash. – choroba

Смежные вопросы