Bash Bug Fix: чтение текстового файла построчно и воздействие на строки - PullRequest
0 голосов
/ 01 ноября 2018

Вот как выглядит мой скрипт

#/bin/bash
touch input.txt
touch output.txt
seq -w 0 999 >>input.txt
input=$(cat input.txt)

for i in $input
  do
    if [ $(($i%2)) -eq 0 ]; then
      echo $i "even" >> output.txt
    else
      echo $i "odd" >> output.txt
   fi
 done

Вот результат запуска скрипта и просмотра созданного файла output.txt

000 even
001 odd
002 even
003 odd
004 even
005 odd
006 even
007 odd

Я бы хотел, чтобы скрипт делал это для всех 1000 строк скрипта, но в строке 9 я получаю сообщение об ошибке, в котором говорится

./tester.sh: line 9: 008: value too great for base (error token is "008")

Моя конечная цель состоит в том, чтобы скрипт добавил каждое число в строке, а затем скажите, является ли число четным или нечетным, и выдает в output.txt все 1000 строк файла.

Выходной файл конечной цели:

000 even
001 odd
002 even
003 odd
...
505 even
506 odd
507 even
508 odd
...
998 even
999 odd

От 000 до 999

Ответы [ 4 ]

0 голосов
/ 13 ноября 2018

Это тоже работает:

#!/bin/bash
for x in `seq -w 0 999`; do
    if [ $((10#$x%2)) == 0 ]; then
        echo $x even
    else
        echo $x odd
    fi
done > output.txt
0 голосов
/ 01 ноября 2018

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

#!/bin/ksh
input=$(seq -w 0 999)
for i in $input
  do
    if [ $(($i%2)) -eq 0 ];then
      echo $i "even" >> output.txt
    else
      echo $i "odd" >> output.txt
    fi
  done

тогда ваш вывод будет что-то вроде

000 even
001 odd
002 even
003 odd
004 even
005 odd
006 even
007 odd

Тогда вы можете использовать grep "even" или "odd" и выполнять то, что вам нужно, или вы можете выполнить свою команду непосредственно внутри оператора if / else.

0 голосов
/ 02 ноября 2018

Используйте seq как seq и используйте printf, чтобы напечатать ваш номер в формате, который вам нравится.
Арифметическое расширение Bash интерпретирует строки с ведущими нулями как восьмеричные числа. Вы можете заставить число быть десятым, добавив к нему префикс 10#, например (( 10#$i % 2)).

for i in $input
  do
    if [ $(( 10#$i % 2)) -eq 0 ]; then
      echo $i "even" >> output.txt
    else
      echo $i "odd" >> output.txt
   fi
 done
  1. Имейте в виду, что арифметическое расширение (( .. )) может выполнять сравнения. Это ясно до if (( 10#$i % 2 == 0 )); then.
  2. Я считаю printf "%03d" "$i" более понятным в этом случае.
  3. Нет необходимости прикасаться к файлу до >>, должен создать файл автоматически (это можно отключить с помощью некоторой опции bash set -o, но я не видел, чтобы кто-нибудь использовал его).
  4. input=$(cat ...); for i in $input просто плохо. Не читать строки с
  5. Мне не нравятся временные файлы.
  6. Как читать файл построчно .

Ваш скрипт просто:

seq 0 999 | xargs -i sh -c 'printf "%03d " "$1"; (( $1 % 2 == 0 )) && echo even || echo odd;'  >>output.txt

Если вы предпочитаете читать,

seq 0 999 | while IFS= read -r num; do 
    printf "%03d " "$num"; 
    if (( num % 2 == 0 )); then 
        echo even
    else
        echo odd
    fi
done >>output.txt

Или, если вам нужен файл input.txt, содержащий 000\n001\n002\n and so on, пришло время для tee:

seq -w 0 999 | tee -a input.txt | while IFS= read -r num; do 
    echo -n "$num "
    if (( 10#$num % 2 == 0 )); then 
        echo even
    else
        echo odd
    fi
done >>output.txt
0 голосов
/ 01 ноября 2018

Это скелетный код для чтения текстового файла построчно и действия по строкам ... Заполните недостающую часть в соответствии со своими потребностями.

#!/bin/bash
{
  while read -r line; do
    if (( line % 2 == 0 )); then
      # ...
    else
      # ...
    fi
  done < input.txt
} > output.txt

Вы также можете применить предварительную обработку к входному файлу с пометкой <(cmd ...):

#!/bin/bash
{
  while read -r line; do
    ...
  done < <(arbitrary-cmd input.txt | another-cmd ... )
} > output.txt

Эта форма выглядит лучше, но порождает "подоболочку" и делает невозможным для кода внутри блока while модифицировать переменные, определенные вне его, если они у вас есть.

#!/bin/bash
{
  arbitrary-cmd input.txt | another-cmd ... | while read -r line; do
    ...
  done
} > output.txt
...