Вопрос или проблема
Обновление: до 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 таких символов.
Технический фон
-
Работа с разделителями: Команда
IFS
(Internal Field Separator) позволяет указать, какой символ будет служить разделителем для командыread
. Это особенно полезно для работы с данными, которые должны быть разделены на основании определенного символа. -
Parameter Expansion: Это мощный механизм в Bash, который позволяет модифицировать значения переменных. Конструкции
${variable%%pattern}
и${variable##pattern}
используются для удаления частей строк справа и слева соответственно. -
Массивы в 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 и массивов позволяет надежно адаптировать скрипт под использование с различными структурами входных данных.