2015-10-02 4 views
2

я написал обертку Пакетное OCR & сценарий службы для тессеракта и abbyyocr11 найти здесь: https://github.com/deajan/pmOCRКак реорганизовать поиск | xargs один вкладыш в читабельный код

Основная функция команда находкой, которая проходит это аргументы xargs с -print0 в чтобы иметь дело со специальными именами файлов. Команда находки стала все более и более сложной и в конечном итоге, как очень длинный один лайнер, который становится трудно поддерживать:

find "$DIRECTORY_TO_PROCESS" -type f -iregex ".*\.$FILES_TO_PROCES" ! -name "$find_excludes" -print0 | xargs -0 -I {} bash -c 'export file="{}"; function proceed { eval "\"'"$OCR_ENGINE_EXEC"'\" '"$OCR_ENGINE_INPUT_ARG"' \"$file\" '"$OCR_ENGINE_ARGS"' '"$OCR_ENGINE_OUTPUT_ARG"' \"${file%.*}'"$FILENAME_ADDITION""$FILENAME_SUFFIX$FILE_EXTENSION"'\" && if [ '"$_BATCH_RUN"' -eq 1 ] && [ '"$_SILENT"' -ne 1 ];then echo \"Processed $file\"; fi && echo -e \"$(date) - Processed $file\" >> '"$LOG_FILE"' && if [ '"$DELETE_ORIGINAL"' == \"yes\" ]; then rm -f \"$file\"; fi"; }; if [ "'$CHECK_PDF'" == "yes" ]; then if ! pdffonts "$file" 2>&1 | grep "yes" > /dev/null; then proceed; else echo "$(date) - Skipping file $file already containing text." >> '"$LOG_FILE"'; fi; else proceed; fi' 

Есть ли лучше способ передать результаты находки читаемой функции (без ущерба для слишком большая скорость)?

Спасибо.

+0

Ответы действительны, но я думаю, что главное здесь было бы исправить * ужасный * скрипт, к которому он обращается. Существует «eval» и множество внешних переменных окружения, которые непосредственно встроены в код. Из использования 'eval' существует чрезмерное цитирование. Условные также могут быть упрощены. –

+0

Я знаю ... в основном, поэтому я разместил это, поскольку он стал все более и более ужасным. Я бы хотел найти ... | функция x, где функция x может быть определена где-то еще в скрипте, но я не нашел способ сделать это красиво. – deajan

+1

Даже не ясно, что вам нужно * 'eval'. Включает ли какой-либо из этих параметров синтаксис оболочки, или они просто имена команд и параметры? – chepner

ответ

2

Вы можете заменить find в целом. Это проще в bash 4 (который я покажу здесь), но выполнимо в bash 3.

proceed() { 
    ... 
} 

shopt -s globstar 

extensions=(pdf tif tiff jpg jpeg bmp pcx dcx) 
for ext in "${extensions[@]}"; do 
    for file in /some/path/**/*."$ext"; do 
    [[ ! -f $file || $file = *_ocr.pdf ]] && continue 
    # Rest of script here 
    done 
done 

bash До 4, вы можете написать свою собственную рекурсивную функцию, чтобы спуститься по иерархии каталогов.

descend() { 
    for fd in "$1"/*; do 
     if [[ -d $fd ]]; then 
      descend "$fd" 
     elif [[ ! -f $fd || $fd != *."$ext" || $fd = *_ocr.pdf ]]; then 
      continue 
     else 
      # Rest of script here 
     fi 
    done 
} 

for ext in "${extensions[@]}"; do 
    descend /some/path "$ext" 
done 
+0

Кажется хорошим решением. Мне нужно будет запустить это на bash 3.2 (centos 5). Массив расширения будет работать, я думаю, что делает bash 3 не обрабатывать, пожалуйста? – deajan

+0

Шаблон '**', который позволяет рекурсивно перебирать все соответствующие файлы. – chepner

+0

Спасибо за помощь. Последний вопрос, поиск производительности против итераций? Любые подсказки (когда есть миллионы файлов и каталогов)? – deajan

3

Не использовать bash -c. Вы уже привержен начать новый bash процесс для каждого файла из команды find, так что просто сохранить код в файл и запустить, что с

find "$DIRECTORY_TO_PROCESS" -type f -iregex ".*\.$FILES_TO_PROCES" \ 
    ! -name "$find_excludes" -print0 | 
    xargs -0 -I {} bash script.bash {} 
+0

Работает, но мне бы очень хотелось, чтобы он остался в том же файле. – deajan

+1

Возможно, вы можете определить и экспортировать функции перед вызовом 'find':' wrapper() {...}; continue() {...}; export -f продолжить обертку; найти ...| xargs -0 -I {} bash -c 'wrapper {}' '. – chepner

2

OK, создать сценарий, а затем запустить поиск.

#!/bin/bash 

trap cleanup EXIT 
cleanup() { rm "$script"; } 

script=$(mktemp) 
cat <<'END' > "$script" 
######################################################################## 
file="$1" 

function proceed { 
    "$OCR_ENGINE_EXEC" "$OCR_ENGINE_INPUT_ARG" "$file" "$OCR_ENGINE_ARGS" "$OCR_ENGINE_OUTPUT_ARG" "${file%.*}$FILENAME_ADDITION$FILENAME_SUFFIX$FILE_EXTENSION" 
    if [ "$_BATCH_RUN" -eq 1 ] && [ "$_SILENT" -ne 1 ]; then 
     echo "Processed $file" 
    fi 
    echo -e "$(date) - Processed $file" >> "$LOG_FILE" 
    if [ "$DELETE_ORIGINAL" == "yes" ]; then 
     rm -f "$file" 
    fi 
} 

if [ "$CHECK_PDF" == "yes" ]; then 
    if ! pdffonts "$file" 2>&1 | grep "yes" > /dev/null; then 
     proceed 
    else 
     echo "$(date) - Skipping file $file already containing text." >> '"$LOG_FILE"'; 
    fi 
else 
    proceed 
fi 
######################################################################## 
END 

find "$DIRECTORY_TO_PROCESS" -type f \ 
          -iregex ".*\.$FILES_TO_PROCES" \ 
          ! -name "$find_excludes" \ 
          -exec bash "$script" '{}' \; 

'END' из Heredoc котируется, поэтому переменные не расширены, пока сценарий не будет на самом деле выполняется.

+0

Делает его понятным для человека, но все еще имеет много двойных/одиночных чисел. Любой способ получить функцию «из команды find», чтобы ее можно было упростить и использовать повторно? – deajan

+0

Возможно, вы могли бы избежать «найти» в целом с помощью соответствующего цикла 'for', но неясно, как это будет выглядеть, не зная значений' $ FILES_TO_PROCES' и '$ find_excludes'. – chepner

+0

Замена обоих значений даст что-то вроде: find/somepath -type f -iregex ". * \. \ (Pdf \ | tif \ | tiff \ | png \ | jpg \ | jpeg \ | bmp \ | pcx \ | dcx \) "! -name "* _ocr.pdf" -print0 | xargs [...] – deajan

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

  • Нет связанных вопросов^_^