Indicizza una stringa in bash


14

Come posso fare riferimento a una stringa per indice in sh / bash? Cioè, fondamentalmente dividendolo.

Sto cercando di eliminare 5 caratteri di un nome file. Tutti i nomi hanno la struttura: name_nr_code. Sto cercando di rimuovere il bit di codice alfanumerico 5. name_nr_ha sempre 10 caratteri.

C'è qualcosa del genere;

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


5
Perché il bashtag se stai chiedendo una shsoluzione?
Stéphane Chazelas,

Risposte:


14

Semplice come questo

(Bash)

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

Ecco.

E una spiegazione da Advanced Bash-Scripting Guide ( Capitolo 10. Manipolazione delle variabili ) , (con le NOTEs in più per evidenziare gli errori in quel manuale):

Estrazione sottostringa

${string:position}

Estrae la sottostringa da $stringa $position.

Se il $stringparametro è "*" o "@", questo estrae i parametri posizionali, iniziando da $position.

${string:position:length}

Estrae i $lengthcaratteri della sottostringa da $stringa $position.

NOTEvirgolette mancanti intorno alle espansioni dei parametri! echonon dovrebbe essere usato per dati arbitrari.

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.

Gli argomenti di posizione e lunghezza possono essere "parametrizzati", cioè rappresentati come una variabile, piuttosto che come una costante numerica.


Se il $stringparametro è "*" o "@", questo estrae un massimo di $lengthparametri posizionali, a partire da $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 substrè un'estensione GNU.

expr substr $string $position $length

Estrae i $lengthcaratteri a $stringpartire da $position.

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

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

NOTE: Questo echoè ridondante e lo rende ancora meno affidabile. Usa expr substr + "$string1" 1 2.

NOTE: exprtornerà con uno stato di uscita diverso da zero se l'uscita è 0 (o -0, 00 ...).


BTW. Il libro è presente nel repository ufficiale di Ubuntu come abs-guide.


Dire "posizione" è leggermente fuorviante in quanto in realtà è un offset, il che significa che ${var:1}non restituisce il valore di vardalla "1a posizione", ma in realtà dalla 2a.
Kusalananda

È vero, ma finché non sei d'accordo ci può essere una posizione zero. Che va bene per me.

9

In POSIX sh,

  • "${var%?????}"è $varprivato degli ultimi 5 caratteri finali (o $varse $varcontiene meno di 5 caratteri)

  • "${var%"${var#??????????}"}"sono i primi 10 caratteri di $var.

  • "${var%_*}"viene $varrimosso dalla stringa più corta che corrisponde _*alla fine di $var( foo_bar_baz-> foo_bar).
  • "${var%%_*}": la stessa partita ma la più lunga invece della partita più breve ( foo_bar_baz-> foo).
  • se si voleva ottenere foo_bar_: "${var%"${var##*_}"}"( ${var##pattern}è lo stesso ${var%%pattern}ma cercare lo schema all'inizio della $varfine anziché alla fine).

Con zsh:

  • $var[1,-6] per il primo personaggio al sesto dalla fine (quindi tutti tranne gli ultimi 5).
  • $var[1,10] per i primi 10 caratteri.

Con ksh, basho zsh:

  • "${var:0:10}": primi 10 caratteri di $var

Con basho zsh:

  • "${var:0:-5}": tutti tranne gli ultimi 5 caratteri (dà un errore ed esce dallo script se $varè impostato ma contiene meno di 5 caratteri, anche quando $varnon è impostato con zsh).

Se hai bisogno della shcompatibilità con Bourne , è molto difficile farlo in modo affidabile. Se puoi garantire che il risultato non finirà con i caratteri di nuova riga, puoi fare:

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\}'`

Avrai anche un limite alla lunghezza di $var(che varia tra i sistemi).

In tutte queste soluzioni, se $varcontiene byte che non possono far parte di caratteri validi, YMMV.


il mio, hanno davvero escogitato una brutta sintassi per dentro quelle parentesi graffe.
gatto

2

shnon fornisce un modo integrato per estrarre una sottostringa da una stringa (per quanto posso vedere), ma con bashte potresti fare

${i:0:10}

Questo ti darà i primi dieci caratteri del valore della variabile i.

Il formato generale è ${variable:offset:length}.


2

La maggior parte delle shell supporta una sorta di espansione dei parametri che può aiutarti. In bash, puoi usare

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

In dash, gli offset non sono supportati, ma puoi usare modelli iniziali e finali:

remove_first3=${string#???}
remove_last2=${string%??}

0

Prima di tutto, non usare un forloop per i nomi dei file.

Quindi, qualcosa del genere dovrebbe aiutare.

find ./ -type f | while read filename ;do
  newfilename=$(echo ${filename}|cut -c 1-10)
  mv ${filename} ${newfilename}
done

3
Perché è male da usare forcon i nomi dei file?
Choroba,

Cita le tue variabili e usale printfper essere più sicuro. ... e read -r.
Kusalananda

3
Il forciclo dell'OP andava bene tranne forse per i dispersi --. Riesco a vedere almeno 10 bug nelle tue 4 righe di codice! molte delle quali cattive pratiche ben note come l'assunzione di nomi di file sono a riga singola, usano l'eco, citazioni mancanti
Stéphane Chazelas
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.