Вопрос или проблема
Я пытаюсь отсортировать список инвентаря в 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
, чтобы никоим образом не нарушить логику программы.
Также рекомендуется добавить обработку ошибок, чтобы убедиться, что файл инвентаря существует и доступен для чтения перед его обработкой.
Эти изменения помогут вам решить проблему сортировки по цене, и ваш скрипт будет работать корректно. Если у вас будут дополнительные вопросы, не стесняйтесь обращаться за разъяснениями или помощью.