Как использовать цикл while внутри subshell после pipe - PullRequest
1 голос
/ 30 марта 2019

Я искал и искал решение для этого, но я не могу найти ничего, что напрямую решает мою проблему. Я пытаюсь добавить строки, добавленные и удаленные некоторыми авторами в git-репо. Я использую git log piped для sed piped to awk, который сейчас пытаюсь передать в подоболочку, чтобы сложить числа. Проблема в том, что вводимые данные не интерпретируются должным образом в подоболочке, и я не могу понять, почему. Я подозреваю, что он находится в цикле while из-за природы синтаксиса subshell и его разбросанности по точкам с запятой.

Я перемещался по коду внутри подоболочки, добавлял и удалял точки с запятой, использовал обратную косую черту для разделения строк, чтобы увидеть, была ли это проблема, и ни одна из них не сработала. Я не очень разбираюсь в оболочке, так что это может быть явно очевидной проблемой для кого-то, кто более опытен. «$ author» - это просто n-й позиционный параметр из командной строки.

for author; do
        echo "Listing file and line changes for $author"
        git log --shortstat --author="$author" ${date:+--since="$date"} \
        | sed -n -e '/files\? changed/s/, /\n/gp' \
        | awk '
            $3=="changed"       {changed+=$1}
            $2=="deletions(-)"  {deletions+=$1}
            $2=="insertions(+)" {insertions+=$1}
            END{
                print "files changed:", changed,
                    " lines removed:", deletions,
                    " lines added:", insertions,
                    " net change:", insertions-deletions
            }'
done | {
      total_changed=0
      total_added=0
      total_removed=0
      while read changed insertions deletions; do
        let total_changed+=changed
        let total_added+=insertions
        let total_removed+=deletions
      done
      echo "totals:"
      echo "files changed: $total_changed"
      echo "lines added: $total_added"
      echo "lines removed: $total_removed" ;
    }

Последняя часть должна выводить итоги, но вместо этого они выводят 0. Я также получаю некоторые странные синтаксические ошибки. Вот результат (вход «Бенджамин Хиллз»):

    /home/bhills/./git-log-lines-removed.sh: line 65: let: and line changes for Benjamin Hills: syntax error in expression (error token is "line changes for Benjamin Hills")
    /home/bhills/./git-log-lines-removed.sh: line 64: let: changed:: syntax error in expression (error token is ":")
    /home/bhills/./git-log-lines-removed.sh: line 65: let: 61  lines removed: 1345  lines added: 246  net change: -1099: syntax error in expression (error token is "lines removed: 1345  lines added: 246  net change: -1099")
    totals:
    files changed: 0
    lines added: 0
    lines removed: 0

1 Ответ

0 голосов
/ 30 марта 2019

Ваш код пытается сгенерировать читабельный вывод дважды : один раз в awk, другой раз в bash.Поскольку выходные данные, генерируемые awk, являются входными данными для bash, это означает, что вы пытаетесь передать формат вывода, предназначенный для людей, и прочитать его так, как если бы это был формат ввода, предназначенный для компьютеров;очевидно, это не так.

Нет никакого веского основания для такого подхода вообще: генерировать все ваш читабельный вывод в одном и том же процессе.

#!/usr/bin/env bash
#              ^^^^- NOT /bin/sh

total_changed=0
total_deletions=0
total_insertions=0

for author; do
  changed=0; deletions=0; insertions=0

  # Loop over output from "git log" for a single author
  while read added deleted _; do
    (( ++changed )) # each line is a file changed
    { [[ $added = - ]] || [[ $deleted = - ]]; } && continue # skip binary files
    (( insertions += added ))
    (( deletions += deleted ))
  done < <(git log --numstat --format='' --author="$author" ${date:+--since="$date"})

  # Print results from that author
  printf '%s\n' "For author: $author" \
                "  Files changed: $changed" \
                "  Deletions: $deletions" \
                "  Insertions: $insertions"

  # Add to totals
  (( total_changed+=changed ))
  (( total_deletions+=deletions ))
  (( total_insertions+=insertions ))
done

# Print those totals
printf '%s\n' "Totals:" \
              "  Files changed: $total_changed" \
              "  Deletions: $total_deletions" \
              "  Insertions: $total_insertions"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...