Разделить строку с 0-2 / (или определить, что их нет) (Bash)

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

Обновление: до 2 “/” в строке.

Структура строки либо:

Название набора символов/LF

Название набора символов/CRLF
Название набора символов/CRLF/(неизвестная цель, вероятно, число)

Название набора символов

Пример: “UTF-8/CRLF”

“UCS-2/CRLF/21”

Т.е. может быть только название набора символов (неизвестно заранее) без какого-либо разделителя “/”.

Название набора символов может содержать “-” и “_” (нет необходимости разделять здесь).

Необходимо присвоить:

VAR1=Название набора символов

VAR2=часть CRLF или LF между 1-м “/” и 2-м “/” (или пустая строка, если нет “/”).

VAR3=Остаток после 2-го “/”.

Какая-то форма true/false (0/1) для VAR2 также подходит (это будет обработано инструкциями if/else позже в скрипте).

Попробовал cut -d/ -f, но cut -d/ -f 2 возвращает “Название набора символов” даже если нет “/”, так что это не работает для меня.

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

Мне нужно вызвать функцию как /bin/bash -c потому что она вызывается в find -exec.

Код (в основном основан на ответе Choroba):

#!/bin/bash
shopt -s extglob

function convert_single_text_file_to_utf8(){

    CUR_FILE_ENCODING_WITH_CRLF=$1
    echo "CUR_FILE_ENCODING_WITH_CRLF=${CUR_FILE_ENCODING_WITH_CRLF}"

    CUR_FILE_ENCODING_ONLY=${CUR_FILE_ENCODING_WITH_CRLF%%/*} # Удалить все, начиная с последнего слэша.
    LINE_FEED=${CUR_FILE_ENCODING_WITH_CRLF##$CUR_FILE_ENCODING_ONLY?(/)} # Удалить набор символов, за которым может следовать слэш.

    echo "CUR_FILE_ENCODING_ONLY=${CUR_FILE_ENCODING_ONLY}   LINE_FEED=${LINE_FEED}"
}

export -f convert_single_text_file_to_utf8

for ENCODING in ASCII UTF-8/CRLF ISO-8859-2/LF EBCDIC-CA-FR; do

    echo "ENCODING=$ENCODING"
    export ENCODING

    /bin/bash -c 'shopt -s extglob; convert_single_text_file_to_utf8 "$ENCODING" '
done

Вы можете разбить строку на индексированный массив var, используя встроенную команду bash shell read, затем извлечь части как ${var[0]} через ${var[2]}:

$ IFS=/ read -ra var <<<"UTF-8/CRLF"
$ declare -p var
declare -a var=([0]="UTF-8" [1]="CRLF")

$ IFS=/ read -ra var <<<"UCS-2/CRLF/21"
$ declare -p var
declare -a var=([0]="UCS-2" [1]="CRLF" [2]="21")
$ echo "Charset: ${var[0]} EOL: ${var[1]}"
Charset: UCS-2 EOL: CRLF

Вы можете использовать расширение параметров для удаления начальных или конечных подстрок из переменных. Они становятся еще более мощными с extglob (используется для конструкции ?(/), которая совпадает с слэшем, если он есть).

#!/bin/bash
shopt -s extglob
for s in UTF-8/CRLF ISO-8859-2/LF EBCDIC-CA-FR; do
    charset=${s%%/*}        # Удалить все, начиная с последнего слэша.
    eol=${s##$charset?(/)}  # Удалить набор символов, за которым может следовать слэш.
    echo "Charset: $charset, end of line: $eol"
done

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

Для решения задачи разбора строковых данных в скрипте Bash необходимо учитывать несколько ключевых аспектов. Давайте разберем теорию, приведем примеры и применим знания к вашему скрипту.

Теория

Разделение строк в Bash может осуществляться с использованием различных средств, таких как утилита cut, команды awk, sed, или возможность работы с массивами, которую предоставляет сам Bash. Основное требование вашей задачи заключается в необходимости выделения различных частей строки, разделенной символом /, при этом стоит учитывать, что строка может содержать от 0 до 2 таких символов.

Технический фон

  1. Работа с разделителями: Команда IFS (Internal Field Separator) позволяет указать, какой символ будет служить разделителем для команды read. Это особенно полезно для работы с данными, которые должны быть разделены на основании определенного символа.

  2. Parameter Expansion: Это мощный механизм в Bash, который позволяет модифицировать значения переменных. Конструкции ${variable%%pattern} и ${variable##pattern} используются для удаления частей строк справа и слева соответственно.

  3. Массивы в Bash: Bash поддерживает одномерные массивы, которые удобно использовать для хранения и манипуляции с данными, которые результатируют из разбиения строки.

Пример

Давайте рассмотрим практическое применение. Представим, что у нас есть строка формата CharacterSetName/LF/AdditionalInfo, где каждая часть несет свое значение.

#!/bin/bash

function parse_string {
    input_string="$1"

    # Установим IFS (Internal Field Separator) как / для разделения строки
    IFS='/' read -ra parts <<< "$input_string"

    var1="${parts[0]}"   # Имя набора символов
    var2="${parts[1]}"   # LF или CRLF
    var3="${parts[2]}"   # Дополнительная информация, если есть

    # Поскольку второй элемент может быть пустым, установим var2 в условный 0 или 1
    if [ -z "$var2" ]; then
        var2_exists=0
    else
        var2_exists=1
    fi

    echo "VAR1=$var1"
    echo "VAR2=$var2"
    echo "VAR3=$var3"
    echo "VAR2 exists: $var2_exists"
}

parse_string "UTF-8/CRLF"
parse_string "UCS-2/CRLF/21"
parse_string "ISO-8859-1"

Применение

Когда вы применяете данные техники, ваш скрипт обретает гибкость и эффективность, особенно когда может сталкиваться с различными форматами входных данных. Отдельное внимание стоит уделить производительности, так как скрипт будет выполнять множество итераций — использование встроенных средств Bash, таких как read и работа с массивами, обеспечивает более высокую скорость по сравнению с вызываемыми внешними программами.

Заключение

Подход с использованием read и массивов Bash подходит для вашей задачи, так как он обеспечит нужную скорость и гибкость при работе с разными форматами строк. Эксплуатация возможностей parameter expansion и массивов позволяет надежно адаптировать скрипт под использование с различными структурами входных данных.

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

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