Was macht% in Linux-Shell-Strings?

28

Was macht% in der Linux-Shell wie folgt:

for file in *.png.jpg; do
  mv "$file" "${file%.png.jpg}.jpg"
done
Nissim Nanach
quelle
4
Jedes Mal , wenn ich diese oben schauen, finde ich in der Regel den rechten Teil der Seite bash man , indem er nach %%oder ##, denn das ist unvergesslich und selten genug , um den rechten Bereich schnell zu finden. man bash /##
Peter Cordes
3
@PeterCordes Ich erinnere mich immer daran: "Es sind 5%, also ist% am Ende und schneidet vom Ende ab. Und es ist # 5, also ist # am Anfang und schneidet vom Anfang ab." Aber manchmal verwechsle ich sogar diesen…
glglgl
2
@glglgl: Bei einer typischen Tastatur #in den USA befindet sich diese unmittelbar links $und %unmittelbar rechts. Keine Gedächtnisstütze nötig - schau einfach nach unten. (Das ist wahrscheinlich zumindest ein Grund, warum diese Symbole ausgewählt wurden.)
Kevin J. Chase
@ KevinJ.Chase Nicht jeder weltweit hat eine typische USA-Tastatur. Auf einer deutschen Tastatur stimmt% jedoch auch mit $ überein, was ein Anfang für das Auswendiglernen sein könnte.
glglgl

Antworten:

29

Wenn %es in pattern verwendet wird ${variable%substring}, wird der Inhalt von variablemit dem kürzesten Vorkommen von substringgelöscht von zurückgegeben variable.

Diese Funktion unterstützt Platzhaltermuster - deshalb akzeptiert sie Stern (Sternchen) als Ersatz für null oder mehr Zeichen.

Es sollte erwähnt werden, dass dies Bash-spezifisch ist - andere Linux-Shells enthalten diese Funktion nicht unbedingt.

Wenn Sie mehr über die Manipulation von Strings in Bash erfahren möchten, empfehle ich dringend, diese Seite zu lesen . Neben anderen praktischen Funktionen erklärt es zum Beispiel, was zu %%tun ist :)

Bearbeiten: Ich habe vergessen zu erwähnen, dass, wenn es in Muster verwendet wird $((variable%number))oder $((variable1%$variable2))das %Zeichen als Modulo-Operator fungiert. DavidPostill hat spezifischere Dokumentationslinks in seiner Antwort.

Wenn %es in einem anderen Kontext verwendet wird, sollte es nur als reguläres Zeichen erkannt werden.

Marek Rost
quelle
2
Der Operator unterstützt Platzhaltermuster und keine regulären Ausdrücke.
Gardenhead
Wie bereits erwähnt, unterstützt gardenhead Glob-Muster und keine regulären Ausdrücke. In regulären Ausdrücken bedeutet ein Stern null oder mehr des vorherigen Zeichens.
Slebetman
5
Das Handbuch, zu dem Sie einen Link erstellt haben, wird von den meisten Benutzern von Unix- und Linux-Stack-Exchange nicht empfohlen . Ich empfehle stattdessen den Wooledge Bash Guide .
Wildcard
3
Die Operatoren zum Entfernen von Präfixen und Suffixen sind Standard und sollten daher in jeder shkompatiblen Shell und nicht nur in Bash verwendet werden können. (obwohl vielleicht nicht in cshund dergleichen).
Ilkkachu
1
Ein weiterer Kontext, in dem %verwendet wird, sind Formatangaben für printf.
Bis auf weiteres angehalten.
9

Bash-Referenzhandbuch: Shell-Parametererweiterung

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

Das Wort wird wie bei der Dateinamenerweiterung erweitert, um ein Muster zu erzeugen. Wenn das Muster mit einem hinteren Teil des erweiterten Werts des Parameters übereinstimmt , ist das Ergebnis der Erweiterung der Wert des Parameters, bei dem das kürzeste Übereinstimmungsmuster (der ‘%’Fall) oder das längste Übereinstimmungsmuster (der ‘%%’Fall) gelöscht wurde. Wenn parameter is ‘@’oder ‘*’,die Musterentfernungsoperation nacheinander auf jeden Positionsparameter angewendet wird, ist die Erweiterung die resultierende Liste. If- Parameter ist eine Array-Variable, die mit ‘@’ oder subskribiert ist‘*’, Die Musterentfernungsoperation wird der Reihe nach auf jedes Mitglied des Arrays angewendet, und die Erweiterung ist die resultierende Liste.

Steven
quelle
2
Hinweis: Einige Parametererweiterungen einschließlich% sind Posix-Features, die von vielen Shells unterstützt werden.
Kojiro
7

Beim Experimentieren stelle ich fest, dass eine Übereinstimmung nach% verworfen wird, wenn die Zeichenfolge in geschweiften Klammern (Klammern) eingeschlossen ist.

Um zu veranschaulichen:

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

Hier ist die Ausgabe:

abcd
abcd%
abcd
abcd

ab
abcd
ab
abcd
abcd%c*
Nissim Nanach
quelle
7

bashWas macht %man in der Linux-Shell ( ) ?

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

In diesem speziellen Fall ist der Operator %is pattern matching (beachten Sie, dass es sich auch um einen Modulo- Operator handeln kann).


Mustervergleichsoperator

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

${var%$Pattern}Entfernen Sie aus $vardem kürzesten Teil, der $Patternmit dem hinteren Ende von übereinstimmt $var.

${var%%$Pattern}Vom $varlängsten Teil entfernen $Pattern, der zum hinteren Ende von passt $var.

Beispiel: Mustervergleich bei der Parametersubstitution

#!/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

Quelle Parameter Substitution


Modulo-Operator

%

modulo oder mod (gibt den Rest einer Ganzzahldivisionsoperation zurück)

bash$ expr 5 % 3
2

5/3 = 1, Rest 2

Source - Operatoren

DavidPostill
quelle
Vielleicht habe ich es verstanden: Dies ist für Dinge wie .*und %definiert es als nicht gierig, während %%es gierig macht? Tatsächlich spielt es im Umbenennungsbeispiel keine Rolle, ob es verwendet werden soll %oder nicht, %%aber wenn es mv "$file" "${file%.*png.jpg}.jpg"(beachte das *) mit %% alle Dateien einfach so umbenennen würde .jpg, oder?
Thomas Weller
@ThomasWeller Ich denke das ist richtig. Aber ich bin kein Bash-Experte.
DavidPostill
"Entfernen ... der kürzeste Teil von $Pattern" ist falsch, da die Variable $Patternim Beispiel nicht definiert ist, sondern nur der Text "Muster" entfernt wird, $varwenn ${var%Pattern}oder ${var%%Pattern}. Vielleicht ist dies nur ein Tippfehler, aber es ist ein weiteres Beispiel dafür, dass tldp.org falsch ist. BashGuide oder Bash Hackers Wiki sind beide imho viel bessere Referenzen.
John B
@ JohnB Danke. Beide Links sind mit einem Lesezeichen versehen. Ich habe den Text in der Antwort korrigiert.
DavidPostill