В bash: захват конечного пробела при подстановке переменных

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

Сочетания клавиш можно найти, выполнив поиск «клавиатура» в меню, перейдя на вкладку сочетаний клавиш, а затем в разделах «Windows» и «Мозаика и привязка».

Удачи.

0
31.03.2020, 04:10
5 ответов

В echo "X${xxx%% }X"шаблон представляет собой один пробел:. Самая длинная совпадающая часть для этого — это :один пробел. Самая короткая совпадающая часть также представляет собой :один пробел.

Для чего-то большего вам понадобится оператор подстановки *. Но это будет соответствовать чему угодно, удалив -Wall. Подстановка Bash не поддерживает прямой эквивалент регулярного выражения a*. Вам понадобится расширенное подстановочное значение:

$ shopt -s extglob
$ echo "X${xxx%%+( )}X"
X-O -WallX
4
19.03.2021, 02:31

Использовать удаление префикса в удалении суффикса:

$ xxx="-O -Wall  "
$ echo "X${xxx%"${xxx##*[! ]}"}X"
X-O -WallX
  • Удалить все до последнего не -символа пробела -оставив только конечные пробелы
  • Используйте эти пробелы в качестве шаблона для удаления суффикса
  • Расширение внутреннего параметра следует заключать в кавычки, чтобы оно не интерпретировалось как шаблон (Не обязательно выше, но может быть полезно в других случаях):
$ bash -c 'xxx="-O -Wall*   "; echo "X${xxx%%"${xxx##*[! *]}"}X"'
X-O -WallX
$ bash -c 'xxx="-O -Wall*   "; echo "X${xxx%%${xxx##*[! *]}}X"'
XX

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


Наблюдаемое вами поведение не является ошибкой, это просто то, как работают простые шаблоны оболочки:

${xxx%% }
  • один пробел — это один пробел
  • самое длинное вхождение одного пробела — это один пробел
${xxx%% *}
  • самое длинное вхождение одного пробела, за которым следует что-либо/ничего
  • ничего/ничего не будет включать-Wall
${xxx% }
  • кратчайшее вхождение одного пробела — это один пробел
${xxx% *}
  • кратчайшее вхождение одиночного пробела, за которым следует что-либо/ничего, является одиночным пробелом
${xxx%% \*}
  • \*— звездочка, экранированная обратной косой чертой, и будет интерпретироваться как буквальная звездочка
  • в переменной нет пробела, за которым следует звездочка, суффикс не удален
6
19.03.2021, 02:31

Это можно сделать с помощью сопоставления регулярных выражений следующим образом:

~> xxx="-O -Wall  "
~> echo "X${xxx}X"
X-O -Wall  X
~> [[ "$xxx" =~ (\ +$) ]]; echo $?,"X${BASH_REMATCH[0]}X"
0,X  X
~> echo "X${xxx%%${BASH_REMATCH[0]}}X"
X-O -WallX

~/src/Perl> xxx="-O -Wall"
~/src/Perl> echo "X${xxx}X"
X-O -WallX
~/src/Perl> [[ "$xxx" =~ (\ +$) ]]; echo $?,"X${BASH_REMATCH[0]}X"
1,XX
~/src/Perl> echo "X${xxx%%${BASH_REMATCH[0]}}X"
X-O -WallX
0
19.03.2021, 02:31

read также может работать (, предполагая, что IFSсодержит «пробел»):

xxx="-O -Wall  "
read -r xxx <<EOF
$xxx
EOF
echo "X${xxx}X"

Выход:

X-O -WallX

  • readразбивает ввод на поля в соответствии сIFS
  • IFSпо умолчанию используется пробел/табуляция/новая строка, поэтому будут удалены все начальные и конечные пробелы
  • Работы над первой строкой переменной (могут не подходить для многострочных переменных, bashможно использоватьread -d '')
1
19.03.2021, 02:31

Простое расширение параметра весьма ограничено шаблонами, которые оно может сопоставлять и удалять. Чтобы удалить несколько (повторяющихся )символов, образующих конец строки, обычное решение состоит в том, чтобы сначала удалить все, что не рассматриваемый символ${xxx##*[! ]}(все конечные пробелы ). Затем, в качестве второго шага, удаление всех результатов этого расширения (всех конечных пробелов )с конца даст вам то, что вы хотите (удалить конечные пробелы ).

$ xxx="-O -Wall  "
$ echo "<${xxx%"${xxx##*[! ]}"}>"
<-O -Wall>

В качестве альтернативы в bash вы можете использовать расширенное подстановочное значение:

$ shopt -s extglob
$ echo "<${xxx%%+( )}>"
<-O -Wall>

Или, в качестве альтернативы более высокого уровня, вы можете сопоставить то, что хотите, с регулярным выражением:

$ regex='(.*[^ ]) +$';
$ [[ $xxx =~ $regex ]] && echo "<${BASH_REMATCH[1]}>" || echo "<$xxx>"
<-O -Wall>

Или,как сценарий:

#!/bin/bash

xxx=${1:-"-O -Wall  "}

regex='(.*[^ ]) +$'

if    [[ $xxx =~ $regex ]]          # if there are trailing spaces
then 
      echo "<${BASH_REMATCH[1]}>"   # Print the string without spaces
else
      echo "<$xxx>"                 # if there are no trailing spaces.
fi
0
19.03.2021, 02:31

Теги

Похожие вопросы