LINUX.ORG.RU

Bash: парсинг параметров

 ,


0

2

Неужели за долгие долгие долгие... ГОДА. В баше так и не сделали нормальный парсинг аргументов из КОРОБКИ? Неужели нужно вечно страдать, втыкать в каждый файлик лапшу из ИИ гугла одну и ту же?

while [[ "$#" -gt 0 ]]; do
    case "$1" in
        -o|--output)
            output_file="$2"
            shift # Consume the argument's value
            ;;
        -v|--verbose)
            verbose=true
            ;;
        -i|--input)
            input_value="$2"
            shift # Consume the argument's value
            ;;
        *)
            echo "Unknown parameter: $1"
            exit 1
            ;;
    esac
    shift # Consume the current argument (flag or unknown)
done


с этими корявыми закорючками, которые никогда не запомнишь?

Вот это вообще что такое?

while [[ "$#" -gt 0 ]]; do


Я до сих пор не могу это понять интуитивно. Кто это вообще придумывал такой синтаксис? Что он ел? Что пил?

;;

Зачем делать 2 точки с запятой?

★★★★

Последнее исправление: gobot (всего исправлений: 2)
Ответ на: комментарий от papin-aziat

чортова совместимость. проще баш выкинуть. (C) x2

а числа с плавающей точкой как складывать?

anonymous
()
Ответ на: комментарий от leave
$ uptime -p
up 1 day, 18 hours, 14 minutes

покажи просто uptime без -p

anonymous
()

ИМХО грамотно написано, я после нескольких лет написания автоматизации к такому пришел.

Вот это вообще что такое?

$# количество аргументов, каждый вызов shift удаляет один аргумент, таким образом происходит проход по аргументам.

anonymous
()
Ответ на: комментарий от debugger

потому что каждый раз экранировать неудобно, чревато ошибками

Когда эти аргументы останавливали разработчиков языка шелла?

unC0Rr ★★★★★
()
Ответ на: комментарий от ext4

Ах, for по числу. Я думал for-each.

Тогда после цикла нужно будет отсечь опции от остаточных аргументов.

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 1)
while getopts ":hs:i:l:p:n" opt; do
  case "$opt" in
  h) usage ;;
  s) SERVER=$OPTARG ;;
  i) INDEX=$OPTARG ;;
  l) LOGIN=$OPTARG ;;
  p) PASSWD=$OPTARG ;;
  n) ADDITIONAL="--silent" ;;
  :) echo "Опция -$OPTARG требует аргумента" >&2; usage ;;
  \?) echo "Неизвестная опция -$OPTARG" >&2; usage ;;
  esac
done

shift "$((OPTIND-1))"   # убираем уже разобранные параметры

if [ "$SERVER" = "" ] || [ "$INDEX" = "" ] || [ "$LOGIN" = "" ] || [ "$PASSWD" = "" ]; then
  echo "Set required arguments"
  usage
fi

vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 3)
Ответ на: комментарий от gobot

неужели за столько лет нельзя написать какую то функцию, эти параметры ведь в каждом скрипте используется

Спорю что какой-то упорыш, который как и ты не понимает что стоит писать на баше а что нет, это таки написал - поищи на каких-нибудь awesome bash помойках.

А в самом баше этого нет и никогда не будет, потому что на нём нормальные люди никогда не станут писать то что требует разбора аргументов.

anonymous
()
Ответ на: комментарий от anonymous

Ой да ладно, часто нужны скрипты примитивные, куча скриптов для управления проектом и с параметрами и без. Ну а что, если не баш? Он везде есть. На питоне, на ноде или пхп что ли, ну скажи еще что на Ц

gobot ★★★★
() автор топика
Ответ на: комментарий от gobot

куча скриптов для управления проектом и с параметрами и без.

Makefile, из новомодных – just

Ну а что, если не баш? Он везде есть.

нет на винде, маке, бздях и еще кое-где

На питоне, на ноде или пхп что ли

а у этих с переносимостью сильно лучше

anonymous
()
Ответ на: комментарий от gobot

неужели за столько лет нельзя написать какую то функцию, эти параметры ведь в каждом скрипте используется…

Это вопрос к самому себе.

Каждый новый скрипт начинается с функции:

arg_parse()
{	# arg_parse	21
  [ "$#" = '0' ] && usage && exit 0
  [ "$#" = '1' ] && case ${1} in
		  --version|-v)	echo "$(basename "$0") ${version}"; exit 0;;
		  *)	;;
		esac
  for i; do
	case ${i} in
	  --arch=*)	arch="${i#--arch=} ${arch}";;
	  --dest=*)	dest=${i#--dest=};;
	  -i=*)		icon=${i#-i=};;
	  --icon=*)	icon=${i#--icon=};;
	  -l=*)		lng=${i#-l=};;
	  --lng=*)	lng=${i#--lng=};;
	  --log)	msg='0'; msg_svc='log';;
	  --log=*)	msg=${i#--log=}; msg_svc='log';;
	  --notify)	msg='0'; msg_svc='notify';;
	  --notify=*)	msg=${i#--notify=}; msg_svc='notify';;
	  --speech)	msg='0'; msg_svc='speech';;
	  --speech=*)	msg=${i#--speech=}; msg_svc='speech';;
	  --src=*)	src=${i#--src=};;
	  --std)	msg='0'; msg_svc='std';;
	  --std=*)	msg=${i#--std=}; msg_svc='std';;
	  -u=*)		util=${i#-u=};;
	  --util=*)	util=${i#--util=};;
	  -v=*)		version=${i#-v=};;
	  --version=*)	version=${i#--version=};;
	  --)		;;
	  *)	if [ -n "${opt}" ]; then opt="${opt} ${i}"; else opt="${i}"; fi;;
	esac
  done
}

Скопировал, вставил, ненужное убрал, нужное по шаблону добавил. Помимо парсинга, при запуске без параметров выводит ‘Usage: …’ (тоже функция), с одним параметром ‘–version’ - показывает версию.

andytux ★★★★★
()
Последнее исправление: andytux (всего исправлений: 1)
Ответ на: комментарий от anonymous

Смешная шутка.

Кстати, как в баше стандартно и легко распарсить параметр - строку (с пробелами) ?

impfp
()
Ответ на: комментарий от debugger

два чаю за getopt но… он тоже парсит говенно.

impfp
()
Ответ на: комментарий от kaldeon

Что не отменяет ошибочного решения сделать баш макро-процессором, из-за чего значения с пробелами могут легко свести с ума скрипты.

kaldeon
()
Ответ на: комментарий от impfp

Как

Не заметил этого слова. Вместо ответа проще привести пример:

; touch test
; chmod +x test
; cat >test <<'EOF'
#!/bin/bash
option=''
args=()
while [[ $# -gt 0 ]]; do case "$1" in
-o)
	option="$2"
	shift 2
	;;
-*)
	echo 1>&2 unexpected option: "$1"
	exit 1
	;;
*)
	args=("$@")
	shift $#
	;;
esac done
echo option: "${#option}" "$option"
echo args: "${#args[@]}" "${args[@]}"
EOF
; ./test -o hello foo bar
option: 5 hello
args: 2 foo bar
; ./test -o 'hello world' foo bar
option: 11 hello world
args: 2 foo bar
kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 2)

Здесь нет ничего специфичного башу кроме [[ ... ]], всё это было ещё в оригинальном sh.

нормальный парсинг аргументов из КОРОБКИ

Программировать целые программы на шелле это такая себе затея. Возможно конечно же, но никто не обещал что это будет удобно. Ну и есть встроенный getopts, ты просто не искал не нашёл.

Вот это вообще что такое?

Пока длина argv больше нуля. $# это магическая переменная означающая длину массива аргументов:

The following parameters are automatically set by the shell.
# The number of positional parameters in decimal.

Зачем делать 2 точки с запятой?

case word in [pattern [| pattern ] ... ) list ;;] ... esac

Это синтаксис оператора case. Спроси у авторов шелла.

neumond
()
Ответ на: комментарий от amd_amd

недавно впервые решил воспользоваться ии и попросил его написать однострок для извлечения времени из uptime и оно мне такую дичь стало предлагать - ни один вариант оказался не рабочим

Хз, у меня ИИ-шка вот такие функции пишет по простейшим промптам. Я только вычитываю и минимальные правки вношу.

# Функция для нарезки видео на фрагменты заданной длины с помощью FFmpeg.
# Использование: split_video <имя_файла> <длительность_фрагмента>
# split_video my_movie.mp4 00:30:00
# split_video "big video file.mkv" 1800 (1800 секунд = 30 минут)
# Created By Gemini 2.5 Pro
split_video() {
  # --- 1. Проверка входных данных ---

  # Проверяем, что передано ровно два аргумента
  if [ "$#" -ne 2 ]; then
    echo "Ошибка: Неверное количество аргументов."
    echo "Использование: $0 <имя_файла> <длительность_фрагмента>"
    echo "Пример: $0 video.mp4 00:30:00"
    return 1
  fi

  local input_file="$1"
  local segment_duration="$2"

  # Проверяем, существует ли входной файл
  if [ ! -f "$input_file" ]; then
    echo "Ошибка: Файл не найден: '$input_file'"
    return 1
  fi

  # Проверяем, установлен ли ffmpeg
  if ! command -v ffmpeg &> /dev/null; then
    echo "Ошибка: команда 'ffmpeg' не найдена. Пожалуйста, установите FFmpeg."
    return 1
  fi

  # --- 2. Подготовка имен файлов ---

  # Извлекаем имя файла без расширения
  local filename=$(basename -- "$input_file")
  local name_no_ext="${filename%.*}"
  # Извлекаем расширение
  local extension="${filename##*.}"

  # Создаем шаблон для выходных файлов
  local output_pattern="${name_no_ext}_%03d.${extension}"

  # --- 3. Выполнение команды ---

  # Запускаем FFmpeg
  ffmpeg -i "$input_file" \
         -c copy \
         -map 0 \
         -segment_time "$segment_duration" \
         -f segment \
         -reset_timestamps 1 \
         "$output_pattern"

  # --- 4. Проверка результата ---

  if [ $? -eq 0 ]; then
    echo "✅ Нарезка видео успешно завершена!"
  else
    echo "❌ Ошибка: FFmpeg завершился с ошибкой. Проверьте вывод выше."
    return 1
  fi
}
wandrien ★★★
()
Ответ на: комментарий от thesis

Баш нельзя улучшать, он лишь станет еще закорючливее и страшнее. Его надо хоронить, но Поттеринг пока занят.

Все виденные мной альтернативы баша выглядят страшнее самого баша.

Так что надежда только на Поттеринга.

wandrien ★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.