цикл for в bash просто печатает n раз команду вместо повторения - PullRequest
0 голосов
/ 04 октября 2019

У меня есть файл input.txt с более чем 6000 строк.

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

Конечный продукт: нет строк, содержащих более 10 слов и запятых, поскольку они содержат всебыл расколот.

Пример:

Ввод

Line 1: This is me, and my sample test line that I like to get working, and I want to be able to kick some ass while doing it

Ожидаемый вывод:

Line 1: This is me, 
Line 2: and my sample test line that I like to get working,
Line 3: and I want to be able to kick some ass while doing it

Я использую следующий код:

#! /bin/bash

for run in {1..7}
do

awk 'NF >= 10 {
sub (", ", ",\n")

}1' input.txt

done

Этот код не дает желаемого результата. Вместо этого я получаю следующий вывод 7 раз.

line 1: This is me,

line 2: and my sample test line that I like to get working, and I want to be able to kick some ass while doing it.

Я склоняюсь к седу, но мне что-то не понятно. Я вижу три подхода: 1) код читает строку (скажем, line7), и в ней более 10 слов, и разбивает ее на запятую (но не проверяет, превышает ли вновь разбитая строка более 10 слов) и переходит на следующую строку. В конце файла, он повторяет этот процесс (скажем, 7 раз), чтобы гарантировать, что новые прерывистые строки также будут меньше 10 слов. ПОТОМ, он берет выходные данные этого процесса и делает то же самое, но с новым условием (например, словом «и»). ПОТОМ, он принимает вывод этого и так далее ... Я могу добавить бесконечные условия. Это подход, который я предпочитаю. Я также думаю, что легче кодировать.

Второй подход 2) Является ли этот код чтением строки, и если он содержит более 10 слов, он разбивает его на запятую, а затем, если все еще более 10 слов, он разбивает это далеечерез запятую и так далее, пока не менее 10 слов. Только тогда он переходит на следующую строку. Я думаю, что это то, что делает код Готи. Но тогда сложно добавить дополнительные условия. 3) 3-й подход заключается в следующем: он разбивает строку на 10 слов через запятую, затем остаток строки прерывается на «и» и так далее. Затем, в конце концов, весь этот процесс повторяется несколько раз. ИМХО это тоже не лучший способ сделать это.

Может кто-нибудь помочь, пожалуйста.

Заранее спасибо!

Ответы [ 2 ]

3 голосов
/ 05 октября 2019

Я думаю, что вижу, что вы после. Есть несколько проблем с вашим подходом:

  • awk не обрабатывает файлы на месте. Таким образом, ваш sub() вносит изменения, 1 печатает на стандартный вывод, но ваш входной файл никогда не меняется.
  • Когда вы sub(), вы не вставляете новую запись во входной поток, который является awkобработка. Ваша команда просто добавляет новую строку к текущей записи.

Учитывая это, вы могли бы избежать обработки входных данных несколько раз, как вы предлагали. Но вместо того, чтобы произвольно предполагать, что у вас будет максимум семь фраз по 10 слов в строке, может быть, лучше определить, нужно ли вам продолжать. Примерно так:

#!/usr/bin/env bash

input=input.txt
temp=$(mktemp ${input}.XXXX)
trap "rm -f $temp" 0

while awk '
  BEGIN { retval=1 }
  NF >= 10 && /, / {
    sub(/, /, ","ORS)
    retval=0
  }
  1
  END { exit retval }
' "$input" > "$temp"; do
  mv -v $temp $input
done

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

0 голосов
/ 07 октября 2019

ОК, вот как я решил эту проблему. Это некрасиво, но это работает. Кроме того, я могу продолжать передавать больше команд sed, чтобы добавить больше условий (как мой комментарий выше @ghoti).

sed -r '/((\w)+[., ]+){10}/s/\./\.\n/' input.txt | sed -r '/((\w)+[., ]+){10}/s/\./\.\n/' | sed -r '/((\w)+[., ]+){10}/s/\./\.\n/' | sed -r '/((\w)+[., ]+){10}/s/\./\.\n/'| sed -r '/((\w)+[., ]+){10}/s/\./\.\n/' | sed -r '/((\w)+[., ]+){10}/s/\./\.\n/' | sed -r '/((\w)+[., ]+){10}/s/\./\.\n/' | tr -s [:space:] > output.txt

По сути, я только 7 раз передавал одну и ту же команду sed (в приведенном выше примере я заменяю точки вместо запятых, но все равно). Исходя из того, что я читаю в режиме онлайн, я удивлен, что эта команда не допускает некоторые рекурсивные / повторные действия. Или, если кто-то знает, пожалуйста, не стесняйтесь редактировать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...