Indizieren Sie eine Zeichenfolge in Bash

14

Wie kann ich in sh / bash nach Index auf einen String verweisen? Das heißt, im Grunde es zu teilen.

Ich versuche, 5 Zeichen eines Dateinamens zu entfernen. Alle Namen haben die Struktur: name_nr_code. Ich versuche, das 5 alphanumerische Codebit zu entfernen. name_nr_ist immer 10 Zeichen.

Gibt es so etwas?

for i in * ; do mv "$i" "$i"[:10] ; done

Pierre B
quelle
5
Warum das bashTag, wenn Sie nach einer shLösung fragen ?
Stéphane Chazelas

Antworten:

14

So einfach ist das.

(Bash)

for i in * ; do mv -- "$i" "${i:0:5}" ; done

Voila.

Und eine Erklärung aus dem Advanced Bash-Scripting Guide ( Kapitel 10. Manipulieren von Variablen ) (mit zusätzlichen NOTEs inline, um die Fehler in diesem Handbuch hervorzuheben):

Teilstrangextraktion

${string:position}

Extrahiert einen Teilstring aus $stringat $position.

Wenn der $stringParameter "*" oder "@" ist, werden die Positionsparameter extrahiert, beginnend mit $position.

${string:position:length}

Extrahiert $lengthZeichen des Teilstrings aus $stringat $position.

NOTEfehlende Anführungszeichen um Parametererweiterungen! echosollte nicht für beliebige Daten verwendet werden.

stringZ=abcABC123ABCabc
#       0123456789.....
#       0-based indexing.

echo ${stringZ:0}                       # abcABC123ABCabc
echo ${stringZ:1}                       # bcABC123ABCabc
echo ${stringZ:7}                       # 23ABCabc 

echo ${stringZ:7:3}                     # 23A
                                        # Three characters of substring.


# Is it possible to index from the right end of the string?

echo ${stringZ:-4}                      # abcABC123ABCabc
# Defaults to full string, as in ${parameter:-default}.
# However . . . 

echo ${stringZ:(-4)}                    # Cabc
echo ${stringZ: -4}                     # Cabc
# Now, it works.
# Parentheses or added space "escape" the position parameter.

Die Position und Länge Argumente können „parametrisiert“ sein , die, dargestellt als eine Variable, und nicht als eine numerische Konstante ist .


Wenn der $stringParameter "*" oder "@" ist, extrahiert dies ein Maximum von $lengthPositionsparametern, beginnend mit $position.

echo ${*:2}          # Echoes second and following positional parameters.
echo ${@:2}          # Same as above.

echo ${*:2:3}        # Echoes three positional parameters, starting at second.

NOTE: expr substrist eine GNU-Erweiterung.

expr substr $string $position $length

Extrahiert $lengthZeichen $stringab $position.

stringZ=abcABC123ABCabc
#       123456789......
#       1-based indexing.

echo `expr substr $stringZ 1 2`           # ab
echo `expr substr $stringZ 4 3`           # ABC

NOTE: Das echoist überflüssig und macht es noch weniger zuverlässig. Verwenden Sie expr substr + "$string1" 1 2.

NOTE: exprwird mit einem Ausgangsstatus ungleich Null zurückgegeben, wenn der Ausgang 0 (oder -0, 00 ...) ist.


Übrigens. Das Buch ist im offiziellen Ubuntu-Repository als vorhanden abs-guide.

tomas
quelle
"Position" zu sagen ist leicht irreführend, da es sich tatsächlich um einen Offset handelt, was bedeutet, dass ${var:1}nicht der Wert von var"1. Position", sondern der Wert von "2. Position" zurückgegeben wird.
Kusalananda
Das stimmt, aber solange Sie nicht zustimmen, kann es eine nullte Position geben. Welches ist in Ordnung mit mir.
9

In POSIX sh,

  • "${var%?????}"wird $varvon den letzten 5 nachgestellten Zeichen befreit (oder $varwenn $varweniger als 5 Zeichen enthalten sind)

  • "${var%"${var#??????????}"}"sind die ersten 10 Zeichen von $var.

  • "${var%_*}"wird $varvon der kürzesten Zeichenfolge befreit, die _*am Ende von $var( foo_bar_baz-> foo_bar) übereinstimmt .
  • "${var%%_*}": Gleiche, aber längste Übereinstimmung anstelle der kürzesten Übereinstimmung ( foo_bar_baz-> foo).
  • wenn du bekommen wolltest foo_bar_: "${var%"${var##*_}"}"( ${var##pattern}ist das selbe wie ${var%%pattern}aber suche das muster am anfang $varstatt am ende).

Mit zsh:

  • $var[1,-6] für das erste Zeichen bis zum 6. vom Ende (also alle bis auf die letzten 5).
  • $var[1,10] für die ersten 10 Zeichen.

Mit ksh, bashoder zsh:

  • "${var:0:10}": die ersten 10 Zeichen von $var

Mit bashoder zsh:

  • "${var:0:-5}": alle bis auf die letzten 5 Zeichen (gibt einen Fehler aus und beendet das Skript, wenn $varfestgelegt, enthält aber weniger als 5 Zeichen, auch wenn $varnicht mit festgelegt zsh).

Wenn Sie Bourne- shKompatibilität benötigen , ist es sehr schwierig, dies zuverlässig zu tun. Wenn Sie sicherstellen können, dass das Ergebnis nicht in Zeilenumbrüchen endet, können Sie Folgendes tun:

first_10=`expr " $var" : ' \(.{1,10\}\)'` # beware the exit status
                                          # may be non-zero if the
                                          # result is 0 or 0000000000

all_but_last_5=`expr " $var" : ' \(.*\).\{5\}'`

Sie können auch die Länge von $var(je nach System unterschiedlich) begrenzen .

Wenn in all diesen Lösungen $varBytes enthalten sind, die nicht Teil gültiger Zeichen sind, wird YMMV verwendet.

Stéphane Chazelas
quelle
Meine Güte, sie haben sich wirklich eine hässliche Syntax für diese Klammern ausgedacht.
Katze
2

shbietet keine eingebaute Möglichkeit, einen Teilstring aus einem String zu holen (soweit ich sehen kann), aber bashSie können es tun

${i:0:10}

Dadurch erhalten Sie die ersten zehn Zeichen des Werts der Variablen i.

Das allgemeine Format ist ${variable:offset:length}.

Kusalananda
quelle
2

Die meisten Shells unterstützen eine Art Parametererweiterung, die Ihnen helfen kann. In Bash können Sie verwenden

substr=${string:4:5} # start at position 4, length 5.

In dashwerden Offsets nicht unterstützt, Sie können jedoch führende und nachfolgende Muster verwenden:

remove_first3=${string#???}
remove_last2=${string%??}
Choroba
quelle
0

Verwenden Sie zunächst keine forSchleife für Dateinamen.

Dann sollte so etwas helfen.

find ./ -type f | while read filename ;do
  newfilename=$(echo ${filename}|cut -c 1-10)
  mv ${filename} ${newfilename}
done
MelBurslan
quelle
3
Warum ist es schlecht, formit Dateinamen zu verwenden?
Choroba
Zitieren Sie Ihre Variablen und verwenden Sie printf, um sicherer zu sein. ... und read -r.
Kusalananda
3
Die OP- forSchleife war in Ordnung, bis auf die fehlenden --. Ich kann mindestens 10 Bugs in Ihren 4 Codezeilen sehen! Viele der bekannten schlechten Praktiken wie die Annahme, dass Dateinamen einzeilig sind, verwenden Echo, fehlende Anführungszeichen
Stéphane Chazelas