Как удалить пробельные символы из переменной Bash?
У меня есть shell-скрипт со следующим кодом:
var=`hg st -R "$path"`
if [ -n "$var" ]; then
echo $var
fi
Но условный код всегда выполняется, потому что hg st всегда выводит как минимум один символ новой строки.
Есть ли простой способ удалить пробельные символы из $var (как trim() в PHP)?
Или есть стандартный способ решения этой проблемы?
Я мог бы использовать sed или AWK, но я бы хотел подумать, что существует более элегантное решение этой проблемы.
Как обрезать пробелы в переменной Bash
Чтобы обрезать пробелы в переменной Bash, можно использовать несколько методов, включая расширение параметров, sed, awk или команду read. Наиболее элегантное решение для вашей проблемы с hg st - использовать шаблоны расширения параметров или команду read для удаления пробелов, а затем проверить, является ли результирующая переменная пустой.
Содержание
- Понимание проблемы с
hg st - Использование расширения параметров для обрезки пробелов
- Использование команды
readдля удаления пробелов - Использование
sedдля обрезки - Использование
trдля простого удаления пробелов - Проверка, является ли переменная пустой после обрезки
- Полное решение для вашей проблемы с
hg st - Сравнение производительности
- Обработка многострочных переменных
Понимание проблемы с hg st
Проблема, с которой вы столкнулись, возникает потому, что команда hg st (Mercurial status) всегда выводит как минимум один символ новой строки, даже когда нет изменений для отображения. Это заставляет Bash рассматривать переменную как непустую, из-за чего ваше условное выражение [ -n "$var" ] всегда выполняется.
Как отмечено в исследованиях, это распространенная проблема при работе с командами, которые выводят символы новой строки или пробельные символы. Ваш исходный код:
var=`hg st -R "$path"`
if [ -n "$var" ]; then
echo $var
fi
Будет всегда выводить результат, потому что var содержит как минимум символ новой строки, что делает его непустым для Bash.
Использование расширения параметров для обрезки пробелов
Bash предоставляет мощные возможности расширения параметров, которые можно использовать для обрезки пробелов без внешних команд. Это часто является наиболее элегантным решением:
Базовые шаблоны обрезки
# Удаление ведущих пробелов
var="${var#"${var%%[![:space:]]*}"}"
# Удаление конечных пробелов
var="${var%"${var##*[![:space:]]}"}"
Более читаемая версия с extglob
shopt -s extglob
var="${var##+( )}" # Удаление ведущих пробелов
var="${var%%+( )}" # Удаление конечных пробелов
shopt -u extglob
Комплексная функция обрезки
trim() {
local var="$1"
# Удаление ведущих пробелов
var="${var#"${var%%[![:space:]]*}"}"
# Удаление конечных пробелов
var="${var%"${var##*[![:space:]]}"}"
printf '%s' "$var"
}
Этот подход очень эффективен, так как использует только встроенные возможности Bash без запуска внешних процессов источник.
Использование команды read для удаления пробелов
Команда read можно использовать для удаления всех ведущих и конечных пробелов из переменной:
var=" hello world "
read -r var <<< "$var"
echo "='$var='" # Вывод: '=hello world='
Для вашей конкретной проблемы с hg st:
var=`hg st -R "$path"`
read -r var <<< "$var"
if [ -n "$var" ]; then
echo "$var"
fi
Это работает потому, что read автоматически удаляет ведущие и конечные пробельные символы (пробелы и табуляции) при чтении в переменную. Однако учтите, что этот метод может не сохранять внутренние пробелы в точности как есть источник.
Использование sed для обрезки
sed - это мощный инструмент для обработки текста, который можно использовать для обрезки пробелов:
Обрезка одной строки
var=" test string "
var=$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' <<< "$var")
Функциональный подход
trim_sed() {
local var="$1"
var=$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' <<< "$var")
printf '%s' "$var"
}
Для многострочных переменных можно использовать опцию GNU Sed -z:
trim_multiline_sed() {
local var="$1"
var=$(printf '%s' "$var" | sed -z 's/^[[:space:]]*//' | sed -z 's/[[:space:]]*$//')
printf '%s' "$var"
}
Подход с sed универсален, но может быть медленнее, чем расширение параметров из-за накладных расходов на запуск внешнего процесса источник.
Использование tr для простого удаления пробелов
Команда tr можно использовать для простого удаления пробелов, хотя она больше подходит для удаления конкретных символов, чем для обрезки:
# Удаление всех пробелов, включая символы новой строки
var=$(echo -n "$var" | tr -d '[:space:]')
# Удаление только символов новой строки
var=$(echo -n "$var" | tr -d '\n')
Для вашей проблемы с hg st можно просто удалить символ новой строки:
var=$(hg st -R "$path" | tr -d '\n')
if [ -n "$var" ]; then
echo "$var"
fi
Этот подход хорошо работает, но удаляет все символы новой строки, что может быть нежелательно, если вам нужно сохранить переносы строк источник.
Проверка, является ли переменная пустой после обрезки
После обрезки необходимо правильно проверить, является ли переменная пустой. Вот несколько подходов:
Использование теста -z
trimmed_var=$(trim "$var")
if [ -z "$trimmed_var" ]; then
echo "Переменная пуста после обрезки"
fi
Использование сопоставления с шаблоном
# Проверка, содержит ли переменная только пробелы
if [[ $var =~ ^[[:space:]]*$ ]]; then
echo "Переменная пуста или содержит только пробелы"
fi
Использование расширения параметров
if [ -n "${var// /[[:space:]]}" ]; then
echo "Переменная содержит непробельные символы"
fi
Эти методы помогают точно определить, содержит ли ваша переменное осмысленное содержимое после обрезки источник.
Полное решение для вашей проблемы с hg st
Вот полное решение с использованием расширения параметров:
#!/bin/bash
path="/путь/к/вашему/репозиторию"
# Получаем статус и обрезаем пробелы
var=$(hg st -R "$path")
var="${var#"${var%%[![:space:]]*}"}" # Удаление ведущих пробелов
var="${var%"${var##*[![:space:]]}"}" # Удаление конечных пробелов
# Проверяем, содержит ли переменное осмысленное содержимое
if [ -n "$var" ]; then
echo "$var"
else
echo "Изменения не обнаружены"
fi
Или с использованием метода read:
#!/bin/bash
path="/путь/к/вашему/репозиторию"
# Получаем статус и обрезаем с помощью read
read -r var <<< "$(hg st -R "$path")"
if [ -n "$var" ]; then
echo "$var"
else
echo "Изменения не обнаружены"
fi
Оба решения правильно обрабатывают случай, когда hg st выводит только символы новой строки источник.
Сравнение производительности
Разные методы имеют разные характеристики производительности:
| Метод | Скорость | Портативность | Возможности |
|---|---|---|---|
| Расширение параметров | Самый быстрый | Только Bash | Ограниченные возможности |
Команда read |
Быстро | POSIX | Хорошо для базовой обрезки |
sed |
Средняя | Универсальная | Мощная, но медленнее |
tr |
Быстро | Универсальная | Хороша для простого удаления |
Для сценариев оболочки, где важна производительность, расширение параметров обычно является лучшим выбором. Для переносимости между разными оболочками метод read является отличным источник.
Обработка многострочных переменных
Если ваша переменная может содержать несколько строк и вам нужно обрезать каждую строку индивидуально, можно использовать цикл:
trim_multiline() {
local var="$1"
local result=""
while IFS= read -r line; do
# Обрезаем каждую строку
line="${line#"${line%%[![:space:]]*}"}"
line="${line%"${line##*[![:space:]]}"}"
# Добавляем непустые строки в результат
if [ -n "$line" ]; then
result+="$line"$'\n'
fi
done <<< "$var"
printf '%s' "$result"
}
Это сохраняет структуру строк, одновременно обрезая пробелы с каждой строки источник.
Заключение
Обрезка пробелов в Bash может быть выполнена несколькими методами, каждый из которых имеет свои преимущества:
- Расширение параметров - наиболее элегантный и эффективный метод, использующий только встроенные возможности Bash
- Команда
read- предоставляет простое, переносимое решение для базовой обрезки sed- предлагает мощное сопоставление с шаблоном для сложных случаевtr- отлично подходит для простого удаления символов
Для вашей конкретной проблемы с hg st наиболее подходящими решениями были бы либо расширение параметров, либо метод read. Оба эффективно удалят конечный символ новой строки, который вызывает выполнение вашего условного оператора.
Ключевой вывод заключается в том, что хотя Bash не имеет встроенной функции trim() как PHP, возможности оболочки по расширению параметров предоставляют мощные инструменты для манипуляции строками, которые одновременно эффективны и элегантны.
Источники
- Stack Overflow - How to trim whitespace from a Bash variable
- Baeldung on Linux - How to Trim Whitespace From a Bash Variable
- nixCraft - Bash Shell Remove & Trim White Spaces From String / Variable
- Reddit r/bash - Remove leading and trailing spaces from a variable
- Unix & Linux Stack Exchange - How do I trim leading and trailing whitespace from each line?
- Greg’s Wiki - BashFAQ/067
- ioflood - How to Trim Whitespace In Bash Shell Scripts
- Goran et al. - Trimming a string with Bash