Замените пробелы на ~ in (ba) sh без внешней команды - PullRequest
1 голос
/ 11 октября 2019

У меня есть строка, которая может содержать несколько пробелов (и табуляции), а также заканчиваться пробелами (но никогда не будет начинаться с пробелов).

Что-то вроде: "topo pippo pluto "

Iнеобходимо удалить пробелы в конце и заменить оставшуюся последовательность пробелов ~. В предыдущем примере я получил бы "topo~pippo~pluto".

В настоящее время я делаю это с:

mystring=$(echo "$mystring" | sed -e 's/\s\s*/~/g' -e 's/~~*$//' ) 

, но я действительно хотел бы найти более быстрый путь (возможно, не имеявызывать внешние команды). Я хотел бы быть независимым от оболочки, но решение для bash тоже подойдет (мне придется использовать bash по другим причинам).

Я пробовал с различными вариантами bash ${}, ноЯ не мог найти решение.

Есть предложения о том, где искать?

Ответы [ 3 ]

3 голосов
/ 11 октября 2019

Решение для оболочки POSIX:

#!/usr/bin/env sh

mystring="topo pippo    pluto   "

# Disable pathname expansion so the parameters expansion
# will not capture pathes if mystring contains patterns
set -f

# Feed mystring as arguments list
# where each space separated element (word) is an argument
set -- $mystring

# Restore pathname expansion
set +f

# Set ~ as the field separator
IFS='~'

# Expand the parameters into mystring with ~ as separator
mystring="$*"

# Restore the default field separator
unset IFS

echo "$mystring" # Print topo~pippo~pluto
3 голосов
/ 11 октября 2019

С Bash:

$ shopt -s extglob
$ str='topo pippo    pluto   '
$ str=${str%%+([[:blank:]])}
$ echo "<$str>"
<topo pippo    pluto>
$ str=${str//+([[:blank:]])/'~'}
$ echo "<$str>"
<topo~pippo~pluto>

Опция extglob необходима для включения шаблона +(pattern). ${str%%+([[:blank:]])} удаляет все пробелы с конца строки;${str//+([[:blank:]])/'~'} заменяет все серии заготовок на ~.

2 голосов
/ 11 октября 2019

Это объясняется в документации bash (запустите man bash на вашем терминале) в разделе «Расширение параметров»:

${parameter/pattern/string}

Замена шаблона . pattern расширяется, чтобы создать шаблон так же, как в раскрытии пути. Parameter раскрывается, и самое длинное совпадение pattern с его значением заменяется на string.
Если pattern начинается с /, все совпадения pattern заменяются string. Обычно заменяется только первое совпадение.
Если pattern начинается с #, оно должно совпадать с началом расширенного значения parameter.
Если pattern начинается с %, онодолжен совпадать в конце расширенного значения parameter.
Если string равно нулю, совпадения pattern удаляются, и следующий шаблон / может быть опущен.
Если параметр @ или *, операция замещения применяется к каждому позиционному параметру по очереди, и расширение является результирующим списком.
Если parameter является переменной массива, подписанной @ или *, операция замещенияприменяется к каждому члену массива по очереди, и расширение является результирующим списком.

Вы не можете выполнить обе замены в одной команде, вы должны использовать ее дважды (один раз, чтобы заменить последовательностипробелов с ~ и один раз для удаления последних ~:

X="topo pippo    pluto   "

# Enable the extended pattern matching
shopt -s extglob

# Replace the sequences of spaces with ~
Y="${X//+( )/\~}"
echo "[$Y]"          # prints: [topo~pippo~pluto~]

# Replace the trailing ~
Z="${Y%\~}"
echo "[$Z]"          # prints: [topo~pippo~pluto]

Примечания:

  • Квадратные скобки в приведенных выше операторах echo не содержат никакихособое значениеграмм. Я использовал их, чтобы четко показать границы строк.
  • ~ - это специальный символ в Bash и других оболочках. Это означает домашний каталог пользователя, и он заменяется его фактическим значением. Его необходимо экранировать, чтобы представлять себя.
  • +( ) - это расширенный шаблон (это означает «один или несколько шаблонов, присутствующих в скобках»);работает только при включенной опции оболочки extglob (с использованием shopt);очевидно, он включен по умолчанию, но в сценариях нельзя полагаться на значения по умолчанию;лучше установить его так, чтобы он работал;
  • ${Y%\~} - это еще один параметр расширения (это также объясняется в документации);удаляет из $Y последний соответствующий суффикс (~);как объяснено выше, ~ необходимо экранировать (\~) для интерпретации как самого себя, а не как домашнего каталога.
...