Рафинирование петли Баш - PullRequest
       8

Рафинирование петли Баш

0 голосов
/ 24 сентября 2018

Здравствуйте, сообщество Stackoverflow,

Пожалуйста, простите меня за наивность, но у меня есть базовый скрипт цикла, выполняющий более сложный скрипт, который ищет текстовый файл для входных данных, которые у меня есть в виде массива.У меня это работает, я думаю, но я знаю, что это можно запустить лучше и автоматизировать.

Вот текстовый файл, к которому смотрит мой скрипт;

2014;14204;
2015;15042;
2015;15062;
...
end;

Вот скрипт bashЯ работаю как цикл;

{ while IFS=';' read  YEAR1 PROJ1 YEAR2 PROJ2 YEAR3 PROJ3 fake
    do 
        { echo "$YEAR1" | egrep '^#|^ *$' ; } > /dev/null && continue 
            $local/script.sh \
                --forinput1 $YEAR1/$PROJ1  \
                --forinput2 $YEAR2/$PROJ2  \
                --forinput3 $YEAR3/$PROJ3  \
    done 
} < textFile.txt

Я провел некоторые исследования сам и обнаружил кое-что, что, как я думал, будет работать, но не смог правильно реализовать это.Если бы вы могли дать мне несколько указателей, я был бы признателен.

Отредактировано: я приношу свои извинения, поэтому скрипт распознает текстовый файл следующим образом:

YEAR1;PROJ1;
YEAR2;PROJ2;
YEAR3;PROJ3;

Использование ";"как его разделитель.Он работает в цикле до последней переменной, которую он сделал.Однако для этой функции мне нужно добавить в текстовый файл дополнительные строки

YEAR4;PROJ4;
YEAR5;PROJ5;
end;

, а затем добавить скрипт

{ while IFS=';' read  YEAR1 PROJ1 YEAR2 PROJ2 YEAR3 PROJ3 YEAR4 PROJ4 YEAR5 PROJ5 fake
    do 
        { echo "$YEAR1" | egrep '^#|^ *$' ; } > /dev/null && continue 
            $local/script.sh \
                --forinput1 $YEAR1/$PROJ1  \
                --forinput2 $YEAR2/$PROJ2  \
                --forinput3 $YEAR3/$PROJ3  \
                --forinput4 $YEAR4/$PROJ4  \
                --forinput5 $YEAR5/$PROJ5  \
    done 
} < textFile.txt

То, что я надеюсь сделать, это добавить переменные в массивно не нужно добавлять дополнительный синтаксис в скрипт

Это не работает, но я думаю, что я смотрю по линиям

{ while IFS=';' read -a YEAR PROJ < textFile.txt
for ((i = 0; i < "${#YEAR[@]};${#PROJ[@]}"; i++)); do
{ echo "$YEAR[$i]" | egrep '^#|^ *$' ; } > /dev/null && continue 
                $local/script.sh \
                    --forinput[$i] ${YEAR[$i]}/${PROJ[$i]}  \
        done 
    }

Ответы [ 2 ]

0 голосов
/ 24 сентября 2018

Ваш код предполагает, что каждая строка ввода имеет 6 полей, что может привести к коду, подобному

sed -nr 's#([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);#$local/script.sh --forinput \1/\2 --forinput \3/\4 --forinput \5/\6#p' textFile.txt
# or shorter
f='([^;]*;)'
sed -nr 's#'$f$f$f$f$f$f'#$local/script.sh --forinput \1/\2 --forinput \3/\4 --forinput \5/\6#p' textFile.txt

Когда вам нужно объединить 3 строки для ввода, вы не должны пытаться быть умными.

# Don't do this
cat textFile.txt | paste -d'X' - - - | tr -d 'X'
# Trying to make
sed -nr 's#'$f$f$f$f$f$f'#$local/script.sh --forinput \1/\2 --forinput \3/\4 --forinput \5/\6#p' <(cat textFile.txt | paste -d'X' - - - | tr -d 'X')

После того, как вы с гордостью представите код, вы увидите, что вам придется сделать код еще хуже, когда вторая строка является комментарием (начинается с '#').Вам нужно заменить cat textFile.txt на grep -Ev '^#|^ *$' testFile.txt.

Если вам нужно связать разные строки, взгляните на awk.
Решение без проверок:

awk -F';' '{line++}
{param=param " --forinput " $1 "/" $2}
line==3 {print "$local/script.sh" param ; param=""; line=0}
' textFile.txt

Вы можете добавить все виды проверок.

0 голосов
/ 24 сентября 2018

Я предполагаю, что ваш входной файл содержит группы из 3 строк, каждая из которых содержит 2 поля, а не строки из 6 полей.

$ cat file
y1a;p1a;
y2a;p2a;
y3a;p3a;
y1b;p1b;
y2b;p2b;
y3b;p3b;

Затем вы можете поместить несколько команд чтения как условие while":

while
     IFS=';' read year1 proj1 x
     IFS=';' read year2 proj2 x
     IFS=';' read year3 proj3 x
do
    echo script \
        --forinput1 "$year1/$proj1" \
        --forinput2 "$year2/$proj2" \
        --forinput3 "$year3/$proj3"
done < file
script --forinput1 y1a/p1a --forinput2 y2a/p2a --forinput3 y3a/p3a
script --forinput1 y1b/p1b --forinput2 y2b/p2b --forinput3 y3b/p3b

Однако это не обрабатывает комментарии и пустые строки.Эта версия выполняет сценарий после 3-й строки (без комментариев / пустых)

$ cat file
# set 1
y1a;p1a;
y2a;p2a;
y3a;p3a;

# set 2
y1b;p1b;
y2b;p2b;
y3b;p3b;

и

n=0
args=()
while IFS=';' read year project x; do
    { [[ $year == *([[:blank:]])"#"* ]] || [[ $year == *([[:blank:]]) ]]; } && continue
    ((n++))
    args+=( "--forinput$n" "$year/$project" )
    if (( n == 3 )); then 
        echo script "${args[@]}"
        args=()
        n=0
    fi
done < file
script --forinput1 y1a/p1a --forinput2 y2a/p2a --forinput3 y3a/p3a
script --forinput1 y1b/p1b --forinput2 y2b/p2b --forinput3 y3b/p3b

Другой подход для обработки произвольных записей для группы:

$ cat file
# set 1
y1a;p1a;
y2a;p2a;
y3a;p3a;
y4a;p4a;
y5a;p5a;
end;

# set 2
y1b;p1b;
y2b;p2b;
y3b;p3b;
end;

$ grep -Pv '^\s*(#|$)' file | awk -F"\n" -v RS="\nend;\n" -v OFS=, '{
    cmd = "script.sh"
    for (i=1; i<=NF; i++) {
        n = split($i, a, /;/)
        cmd = sprintf( "%s --forinput%d \"%s/%s\"", cmd, i, a[1], a[2])
    }
    print cmd
}'
script.sh --forinput1 "y1a/p1a" --forinput2 "y2a/p2a" --forinput3 "y3a/p3a" --forinput4 "y4a/p4a" --forinput5 "y5a/p5a"
script.sh --forinput1 "y1b/p1b" --forinput2 "y2b/p2b" --forinput3 "y3b/p3b"

Использует grep для фильтрации комментариев и пустых строк.Затем awk приходит для форматирования команд:

  • RS - это разделитель record с использованием наборов end; line
  • -F"\n" поле разделитель новой строки
  • , затем мы перебираем количество полей (NF), чтобы создать команду, которую вы хотите запустить, и выводим ее на печать.

Чтобы фактически выполнить это, перенаправьте вывод awk в | sh

...