Пытаюсь отсортировать с помощью getopts с разными командами и не могу отсортировать по цене.

Вопрос или проблема

Я пытаюсь отсортировать список инвентаря в unix/linux ниже. Мне удалось отсортировать по имени и идентификатору, и я смог вызвать меню использования, но не могу отсортировать по цене, даже с помощью функции “awk”.

Я вызываю код с помощью ./invOpt -p, и вывод продолжает говорить мне, что это недопустимый параметр: -p, затем вызывает меню использования ниже. Я в замешательстве, потому что он отказывается сортировать 4-е поле, где указана цена. Я не знаю, мешает ли символ $ и/или запятая сортировке.

"Использование: invOpts -i | -n | -p | -h
"  -i  сортировать по идентификатору продукта"
"  -n  сортировать по имени продукта"
"  -p  сортировать по цене"
"  -h  показать использование"
МЕНЮ ИНВЕНТАРЯ:
Идентификатор продукта   Название продукта                   Количество   Цена        Общая стоимость
-----------  ------------------------------ --------   -----        -----------
P101        Apple MacBook Pro           25      $2,399.99       $59,999.75
P102        Samsung Galaxy S23          40      $799.99         $31,999.60
P103        Apple iPhone 15             60      $999.99         $59,999.40
P104        Google Pixel 8              35      $899.99         $31,499.65
P105        Microsoft Surface Pro 9     18      $1,299.99       $23,399.82
P106        Dell XPS 13                 50      $1,099.99       $54,999.50
P107        Apple iPad Air              75      $599.99         $44,999.25
P108        Fitbit Charge 5             100     $179.95         $17,995.00
P109        Amazon Echo Dot 5th Gen     150     $49.99          $7,498.50
P110        Sonos One SL                80      $199.99         $15,999.20
P111        Logitech MX Master 3        120     $99.99          $11,998.80
P112        HP Spectre x360             25      $1,499.99       $37,499.75
P113        GoPro Hero 11               60      $399.99         $23,999.40
P114        Nintendo Switch OLED        45      $349.99         $15,749.55
P115        Canon EOS R6                15      $2,499.99       $37,499.85
P116        Seagate 2TB Внешний жесткий диск 200     $69.99          $13,998.00
P117        Apple AirPods Pro 2-го поколения   130     $249.99         $32,498.70
P118        MSI GeForce RTX 4070        40      $599.99         $23,999.60
P119        Lenovo ThinkPad X1 Carbon   20      $1,799.99       $35,999.80
P120        Anker PowerCore 26800       180     $59.99          $10,798.20

ТЕКУЩИЙ КОД:

#!/bin/bash

# Функция для отображения информации об использовании
usage() {
    echo "Использование: invOpts -i | -n | -p | -h"
    echo "  -i  сортировать по идентификатору продукта"
    echo "  -n  сортировать по имени продукта"
    echo "  -p  сортировать по цене"
    echo "  -h  показать использование"
}

# Обработка параметров командной строки с помощью getopts
while getopts ":inp:h" opt; do
    case $opt in
        i)
            # Сортировать по идентификатору продукта (Поле 1) и сохранить в временный файл
            tempFile="/tmp/inventory_sorted_by_id_$$.txt"
            sort -t: -k1,1 ~/A09/inventory > "$tempFile"
            ;;
        n)
            # Сортировать по имени продукта (Поле 2) и сохранить в временный файл
            tempFile="/tmp/inventory_sorted_by_name_$$.txt"
            sort -t: -k2,2 ~/A09/inventory > "$tempFile"
            ;;
        p)
            # Сортировать по цене (Поле 4) и сохранить в временный файл
            tempFile="/tmp/inventory_sorted_by_price_$$.txt"
            sort -t: -k4,4n ~/A09/inventory > "$tempFile"
            ;;
        h)
            # Показать использование и выйти
            usage
            exit 0
            ;;
        ?)
            # Обработать недопустимые параметры
            echo "Недопустимый параметр: -$OPTARG"
            usage
            exit 1
            ;;
    esac
done

# Если параметр не предоставлен, по умолчанию использовать оригинальный файл
if [[ -z $tempFile ]]; then
    tempFile=~/A09/inventory
fi

# Подключить скрипт myFunctions для использования функции chkFile
source ~/Homework9/myFunctions

# Сохранить имя файла инвентаря
filename=~/A09/inventory

# Проверить, существует ли файл, используя chkFile
chkFile $filename
if [[ $? -ne 0 ]]; then
    echo "Ошибка: Файл инвентаря не существует."
    exit 1
fi

# Вывести заголовок
printf "%-12s %-30s %-10s %-15s %-15s\n" "Идентификатор продукта" "Название продукта" "Количество" "Цена" "Общая стоимость"
printf "%-12s %-30s %-10s %-15s %-15s\n" "-----------" "------------------------------" "--------" "-----" "-----------"

# Инициализировать общую стоимость инвентаря
totalInventoryValue=0

# Читать отсортированный файл построчно (либо отсортированный, либо оригинальный)
while IFS=: read -r productID productName quantity price; do
    # Рассчитать общую стоимость: Количество * Цена
    totalValue=$(echo "$quantity * $price" | bc -l)

    # Отформатировать цену и общую стоимость с запятыми
    formattedPrice=$(echo $price | sed ':a;s/\B[0-9]\{3\}/,&/;ta')
    formattedTotalValue=$(echo $totalValue | sed ':a;s/\B[0-9]\{3\}/,&/;ta')

    # Вывести отформатированные данные
    printf "%-12s %-30s %-10s $%-14s $%-14s\n" "$productID" "$productName" "$quantity" "$formattedPrice" "$formattedTotalValue"

    # Добавить общую стоимость к общей стоимости инвентаря
    totalInventoryValue=$(echo "$totalInventoryValue + $totalValue" | bc -l)
done < "$tempFile"

# Отформатировать общую стоимость инвентаря с запятыми
formattedTotalInventoryValue=$(echo $totalInventoryValue | sed ':a;s/\B[0-9]\{3\}/,&/;ta')

# Вывести общую стоимость инвентаря
printf "\nОбщая стоимость инвентаря: $%-14s\n" "$formattedTotalInventoryValue"

# Удалить временный файл
rm -f "$tempFile"

Вы сталкиваетесь с таким поведением (из вывода help getopts):

Если обязательный аргумент не найден, getopts помещает ':' в NAME и устанавливает OPTARG на найденный символ параметра.

Когда вы пишете:

./invOpt -p

Вы упускаете обязательный аргумент, потому что вы определили опцию -p как p: в вашем вызове getopts:

while getopts ":inp:h" opt; do

Поэтому, когда вы пишете -p без следующего аргумента, opt устанавливается на :. Так как у вас нет явного обработчика для этого случая, это приводит к попаданию в ваш раздел по умолчанию:

        ?)
            # Обработать недопустимые параметры
            echo "Недопустимый параметр: -$OPTARG"
            usage
            exit 1
            ;;

И поэтому вы получаете ошибку "недопустимый параметр". Не похоже, что ваш код действительно ожидает значение для опции -p, поэтому простейшее решение - переписать ваш вызов getopts следующим образом:

while getopts ":inph" opt; do

Ответ или решение

Ваш вопрос о сортировке инвентарного списка в Unix/Linux довольно актуален и поднимает несколько важных моментов, которые стоит обсудить для того, чтобы вы смогли успешно сортировать данные по цене. Давайте разберем это по пунктам.

1. Ошибка в обработке параметров

В вашем коде getopts используется для обработки входных аргументов. Вы определили параметры как :inp:h, что подразумевает, что -p требует аргумент (так как за п следует двоеточие). Однако, как видно из вашего вызова ./invOpt -p, вы не передаете никаких аргументов. Когда getopts не получает ожидаемого аргумента для -p, он помещает двоеточие в opt, что и приводит к ошибке "invalid option: -p".

Решение: Вам нужно изменить вашу строку getopts на while getopts ":inph" opt; do. Это позволит вашей программе правильно обработать -p как параметр без аргумента.

2. Сортировка по цене с помощью sort

Также необходимо учесть, что вы используете символы доллара и запятые в ваших значениях цен. Это может помешать корректной сортировке. Ваша команда сортировки:

sort -t: -k4,4n ~/A09/inventory > "$tempFile"

здесь ожидает числовые значения для правильной сортировки. Однако символ доллара $ и профилактические запятые могут не позволить sort обработать ваши данные как числа.

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

awk -F: '{gsub(/\$/,"",$4); gsub(/,/,"",$4); print $0}' ~/A09/inventory | sort -t: -k4,4n > "$tempFile"

Эта команда сначала удаляет символ $ и запятые из четвертого поля (цены), а затем сортирует данные по цене в числовом формате.

3. Завершение

После внесения изменений вам следует протестировать ваш код с другими командами, чтобы убедиться, что он работает так, как ожидается. Обязательно проверьте все параметры -i, -n и -h, чтобы никоим образом не нарушить логику программы.

Также рекомендуется добавить обработку ошибок, чтобы убедиться, что файл инвентаря существует и доступен для чтения перед его обработкой.

Эти изменения помогут вам решить проблему сортировки по цене, и ваш скрипт будет работать корректно. Если у вас будут дополнительные вопросы, не стесняйтесь обращаться за разъяснениями или помощью.

Оцените материал
Добавить комментарий

Капча загружается...