Что% делает в строках оболочки Linux?


28

В оболочке Linux, что делает%, как в:

for file in *.png.jpg; do
  mv "$file" "${file%.png.jpg}.jpg"
done

4
Каждый раз, когда я просматриваю это, я обычно нахожу правильный раздел справочной страницы bash, ища %%или ##, так как это запоминающееся и достаточно редкое место, чтобы быстро найти нужный раздел. man bash /##
Питер Кордес

3
@PeterCordes Я всегда вспоминаю это как «Это 5%, поэтому% находится в конце и, следовательно, сокращается с конца. И это # ​​5, поэтому # находится в начале и сокращается с начала». Но иногда я даже
путаю

2
@glglgl: На типичной клавиатуре США, #находится сразу слева от $, и %сразу же справа. Мнемоника не нужна - просто посмотрите вниз. (Это, вероятно, по крайней мере, часть того, почему эти символы были выбраны.)
Кевин Дж. Чейз,

@ KevinJ.Chase Не у всех в мире есть типичная клавиатура США. Но на немецкой клавиатуре, действительно,% также прав от $, что может стать началом для запоминания.
glglgl

Ответы:


29

Когда %используется в шаблоне, ${variable%substring}он будет возвращать содержимое variableс кратчайшим вхождением, substringудаленным из задней части variable.

Эта функция поддерживает шаблоны подстановочных знаков - поэтому она принимает звездочку (звездочку) в качестве замены для нуля или более символов.

Следует отметить, что это специфично для Bash - другие оболочки linux не обязательно содержат эту функцию.

Если вы хотите узнать больше о работе со строками в Bash, я настоятельно рекомендую прочитать эту страницу. Среди других полезных функций это, например, объясняет, что делает %%:)

Изменить: Я забыл упомянуть , что , когда он используется в шаблоне $((variable%number))или персонаж будет функционировать в качестве оператора по модулю. DavidPostill имеет более конкретные ссылки на документацию в своем ответе.$((variable1%$variable2))%

Когда %используется в другом контексте, он должен распознаваться только как обычный символ.


2
Оператор поддерживает шаблоны подстановочных знаков , а не регулярные выражения.
садовник

Как упоминалось gardenhead - он поддерживает шаблоны глобуса, а не регулярные выражения. В регулярном выражении звезда означает ноль или более предыдущего символа.
Slebetman

5
Руководство, на которое вы ссылаетесь, очень не рекомендуется большинством пользователей Unix & Linux . Вместо этого я рекомендую Wooledge Bash Guide .
Уайлдкарт

3
Операторы удаления префиксов и суффиксов являются стандартными , поэтому их следует использовать в любой sh-совместимой оболочке, а не только в Bash. (хотя, возможно, не в cshи тому подобное).
ilkkachu

1
Другой контекст, в котором %используется, находится в спецификаторах формата для printf.
Приостановлено до дальнейшего уведомления.

9

Справочное руководство Bash: Расширение параметров оболочки

${parameter%word}
${parameter%%word}

Слово раскрывается , чтобы получить шаблон так же , как в расширении имени файла. Если шаблон соответствует завершающей части расширенного значения параметра , то результатом расширения является значение параметра с удаленным самым коротким соответствующим шаблоном ( ‘%’регистр) или самым длинным соответствующим шаблоном ( ‘%%’регистр). Если параметр равен ‘@’или ‘*’,операция удаления шаблона применяется к каждому позиционному параметру по очереди, и расширение является результирующим списком. Если параметр является переменной массива, подписанной с ‘@’ или‘*’, операция удаления шаблона применяется к каждому члену массива по очереди, и расширение является результирующим списком.


2
Примечание: некоторые расширения параметров, включая%, - это функции posix, которые поддерживаются многими оболочками.
Кодзиро

7

Экспериментируя, я обнаружил, что совпадение после% отбрасывается, когда строка заключена в фигурные скобки (фигурные скобки).

Проиллюстрировать:

touch abcd         # Create file abcd

for file in ab*; do
 echo $file        # echoes the filename
 echo $file%       # echoes the filename plus "%"
 echo ${file%}     # echoes the filename
 echo "${file%}"   # echoes the filename
 echo
 echo "${file%c*}" # Discard anything after % matching c*
 echo "${file%*}"  # * is not greedy
 echo ${file%c*}   # Without quotes works too
 echo "${file%c}"  # No match after %, no effect
 echo $file%c*     # Without {} fails
done

Вот вывод:

abcd
abcd%
abcd
abcd

ab
abcd
ab
abcd
abcd%c*

7

В Linux shell ( bash), что делает %?

for file in *.png.jpg; do
  mv "$file" "${file%.png.jpg}.jpg"
done

В этом конкретном случае %это оператор сопоставления с образцом (обратите внимание, что он также может быть оператором по модулю ).


Оператор сопоставления с образцом

$ {var% $ Pattern}, $ {var %% $ Pattern}

${var%$Pattern}Удалить из $varсамой короткой части, $Patternкоторая соответствует заднему концу $var.

${var%%$Pattern}Удалить из $varсамой длинной части, $Patternкоторая соответствует заднему концу $var.

Пример: сопоставление с образцом при подстановке параметров

#!/bin/bash
# patt-matching.sh

# Pattern matching  using the # ## % %% parameter substitution operators.

var1=abcd12345abc6789
pattern1=a*c  # * (wild card) matches everything between a - c.

echo
echo "var1 = $var1"           # abcd12345abc6789
echo "var1 = ${var1}"         # abcd12345abc6789
                              # (alternate form)
echo "Number of characters in ${var1} = ${#var1}"
echo

echo "pattern1 = $pattern1"   # a*c  (everything between 'a' and 'c')
echo "--------------"
echo '${var1#$pattern1}  =' "${var1#$pattern1}"    #         d12345abc6789
# Shortest possible match, strips out first 3 characters  abcd12345abc6789
#                                     ^^^^^               |-|
echo '${var1##$pattern1} =' "${var1##$pattern1}"   #                  6789      
# Longest possible match, strips out first 12 characters  abcd12345abc6789
#                                    ^^^^^                |----------|

echo; echo; echo

pattern2=b*9            # everything between 'b' and '9'
echo "var1 = $var1"     # Still  abcd12345abc6789
echo
echo "pattern2 = $pattern2"
echo "--------------"
echo '${var1%pattern2}  =' "${var1%$pattern2}"     #     abcd12345a
# Shortest possible match, strips out last 6 characters  abcd12345abc6789
#                                     ^^^^                         |----|
echo '${var1%%pattern2} =' "${var1%%$pattern2}"    #     a
# Longest possible match, strips out last 12 characters  abcd12345abc6789
#                                    ^^^^                 |-------------|

# Remember, # and ## work from the left end (beginning) of string,
#           % and %% work from the right end.

echo

exit 0

Подстановка исходного параметра


Оператор по модулю

%

по модулю или mod (возвращает остаток от операции целочисленного деления)

bash$ expr 5 % 3
2

5/3 = 1, с остатком 2

Операторы источника


Может быть, я понял: это для таких вещей, как .*и %определяет, что это не жадный, тогда как %%делает его жадным? Так что на самом деле в примере переименования не имеет значения, использовать %или использовать ( %%но mv "$file" "${file%.*png.jpg}.jpg"обратите внимание на *), используя %%, переименуйте все файлы просто .jpg, верно?
Томас Веллер

@ThomasWeller Я думаю, это правильно. Но я не эксперт по Bash.
ДэвидПостилл

Сказать «Удалить ... самую короткую часть $Pattern» неверно, так как переменная $Patternне определена в примере, только текст «Шаблон» удаляется $varпри выполнении ${var%Pattern}или ${var%%Pattern}. Может быть, это просто опечатка, но это еще один пример неправильной работы tldp.org. BashGuide или Bash Hackers Wiki - намного лучшие ссылки imho.
Джон Б

@JohnB Спасибо. Обе ссылки в закладки. Я исправил текст в ответе.
DavidPostill
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.