Extras subșir în Bash

Având un nume de fișier în formă someletters_12345_moreleters.ext, vreau sa extrag 5 cifre și le-a pus într-o variabilă.

Deci, pentru a sublinia ideea, am un fisier cu x numărul de caractere apoi o perioada de cinci cifre secvență înconjurat de o singură subliniere pe fiecare parte apoi de un alt set de x numărul de caractere. Vreau să iau număr de 5 cifre și a pus într-o variabilă.

Sunt foarte interesat de numărul de moduri diferite în care acest lucru poate fi realizat.

Comentarii la întrebare (3)

Dacă x este constantă, următorul parametru de expansiune efectuează subșir de extracție:

b=${a:12:5}

în cazul în care 12 este offset (zero-based) și 5 este lungimea

Dacă subliniaza jurul cifre sunt doar cele de la intrare, puteți benzi pe prefix și sufix (respectiv) în două etape:

tmp=${a#*_}   # remove prefix ending in "_"
b=${tmp%_*}   # remove suffix starting with "_"

Dacă există și alte subliniază, l's, probabil, posibil, oricum, deși mai complicat. Dacă cineva știe cum de a efectua ambele expansion-uri într-o singură expresie, am'd vrea să știe.

Ambele soluții prezentate sunt pur bash, cu nici un proces de depunere a icrelor implicate, prin urmare, foarte rapid.

Comentarii (12)
Soluția

Folosi cut:

echo 'someletters_12345_moreleters.ext' | cut -d'_' -f 2

Mai generic:

INPUT='someletters_12345_moreleters.ext'
SUBSTRING=$(echo $INPUT| cut -d'_' -f 2)
echo $SUBSTRING
Comentarii (7)

Generic soluție în cazul în care numărul poate fi oriunde în nume de fișier, folosind prima de astfel de secvențe:

number=$(echo $filename | egrep -o '[[:digit:]]{5}' | head -n1)

O altă soluție pentru a extrage exact o parte a unei variabile:

number=${filename:offset:length}

Dacă numele fișierului dvs. întotdeauna au format stuff_digits_... poti folosi awk:

number=$(echo $filename | awk -F _ '{ print $2 }')

Încă o soluție pentru a elimina totul, cu excepția cifre, utilizare

number=$(echo $filename | tr -cd '[[:digit:]]')
Comentarii (1)

doar încercați să utilizați cut-c startIndx-stopIndx

Comentarii (7)

În cazul în care cineva vrea mai riguroase informații, puteți căuta, de asemenea, că în om bash astfel de prognoze

$ man bash [press return key]
/substring  [press return key]
[press "n" key]
[press "n" key]
[press "n" key]
[press "n" key]

Rezultatul:

${parametru:offset}
${parametru:offset:lungime}
Subșir De Expansiune. Se extinde până la o lungime de caractere
parametru pornind de la caracterul specificat de offset. Dacă
lungimea este omis, se extinde la subșir de parametrul start‐
ing la caracterul specificat de offset. lungimea și offset sunt
expresiile aritmetice (a se vedea ARITMETICĂ de EVALUARE de mai jos). Dacă
offset evaluează la un număr mai mic decât zero, valoarea este folosit
ca o compensare la sfârșitul anului valoarea de parametru. Aritmetica
expresii care încep cu o - trebuie să fie separate prin spatii
de precedent : să fie distins de a Folosi Implicit
Valorile de expansiune. Dacă lungimea se evaluează la un număr mai mic decât
zero, și parametru nu este @ și nu un indexate sau asociative
matrice, este interpretat ca un offset de la sfârșitul anului valoarea
de parametru, mai degrabă decât un număr de caractere, și extinderii
sion este de caractere între două compensează. Dacă parametrul este
@, rezultatul este lungimea de poziție parametrii începând de la off‐
set. Dacă parametrul este o indexat numele cotizanti de @ sau
*, rezultatul este lungimea membrii de matrice începând cu
${parametru[offset]}. Un offset negativ este luată relativă a
unul mai mare decât valoarea maximă a indicelui de specificat matrice. Sub‐
șir de expansiune aplicat un tablou asociativ produce unde‐
amendat rezultate. Rețineți că un offset negativ trebuie să fie separate
din colon prin cel puțin un spațiu pentru a nu fi confundat
cu :- expansiune. Subșir de indexare este bazat pe zero, cu excepția cazului în
la parametrii de poziție sunt utilizate, caz în care indexarea
incepe de la 1 în mod implicit. Dacă diferența este 0, și pozițional
parametrii sunt utilizate, $0 este prefixat la lista.
Comentarii (1)

Clădirea de pe jor's raspuns (care nu't de lucru pentru mine):

substring=$(expr "$filename" : '.*_\([^_]*\)_.*')
Comentarii (1)

Am'm-a surprins acest lucru pur bash soluție n't veni:

a="someletters_12345_moreleters.ext"
IFS="_"
set $a
echo $2
# prints 12345

Probabil că doriți să resetați IFS pentru ce valoare a fost înainte, sau `unset FI după aceea!

Comentarii (3)

Aici's cum am'd face:

FN=someletters_12345_moreleters.ext
[[ ${FN} =~ _([[:digit:]]{5})_ ]] && NUM=${BASH_REMATCH[1]}

Notă: cele de mai sus este o expresie regulată și este limitată la scenariu specific de cinci cifre înconjurat de subliniere. Schimba expresia regulată dacă aveți nevoie de diferite de potrivire.

Comentarii (3)

Următoarele cerințe

am un fisier cu x numărul de caractere apoi o perioada de cinci cifre secvența înconjurat de o singură subliniere pe fiecare parte apoi un alt set de x numărul de caractere. Vreau să iau număr de 5 cifre și pune că într-o variabilă.

Am găsit niște grep moduri în care pot fi utile:

$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]+" 
12345

sau mai bine

$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]{5}" 
12345

Și apoi, cu -Po sintaxa:


$ echo "someletters_12345_moreleters.ext" | grep -Po '(?
Comentarii (1)

Fără nici o sub-procese puteți:

shopt -s extglob
front=${input%%_+([a-zA-Z]).*}
digits=${front##+([a-zA-Z])_}

O foarte mică variantă de acest lucru va lucra, de asemenea, în ksh93.

Comentarii (0)

Dacă ne concentrăm în conceptul de:
"O (una sau mai multe) cifre"

Am putea folosi mai multe instrumente externe pentru a extrage numere.
Am putea destul de ușor de a șterge toate celelalte personaje, fie sed sau tr:

name='someletters_12345_moreleters.ext'

echo $name | sed 's/[^0-9]*//g'    # 12345
echo $name | tr -c -d 0-9          # 12345

Dar dacă $numele conține mai multe serii de numere, cele de mai sus va eșua:

Dacă "nume=someletters_12345_moreleters_323_end.ext", atunci:

echo $name | sed 's/[^0-9]*//g'    # 12345323
echo $name | tr -c -d 0-9          # 12345323

Avem nevoie de a utiliza expresii regulate (regex). Pentru a selecta numai primul termen (12345 nu 323) în sed și perl:

echo $name | sed 's/[^0-9]*\([0-9]\{1,\}\).*$/\1/'
perl -e 'my $name='$name';my ($num)=$name=~/(\d+)/;print "$num\n";'

Dar am putea la fel de bine face direct în bash(1) :

regex=[^0-9]*([0-9]{1,}).*$; \
[[ $name =~ $regex ]] && echo ${BASH_REMATCH[1]}

Acest lucru ne permite de a extrage PRIMUL termen de cifre de orice lungime înconjurat de orice alt text/caractere.

Notă: regex=[^0-9]*([0-9]{5,5}).*$; se va potrivi numai exact 5 cifre ruleaza. :-)

(1): mai repede decât de asteptare un instrument extern pentru fiecare texte scurte. Nu mai rapid decât a face toate de prelucrare în interiorul sed sau awk pentru fișiere mari.

Comentarii (0)

Aici's un prefix-sufix soluție (similar cu soluțiile date de JB și Rodger) care se potrivește primul bloc de cifre și nu depinde de cei din jur subliniază:

str='someletters_12345_morele34ters.ext'
s1="${str#"${str%%[[:digit:]]*}"}"   # strip off non-digit prefix from str
s2="${s1%%[^[:digit:]]*}"            # strip off non-digit suffix from s1
echo "$s2"                           # 12345
Comentarii (0)

Îmi place sed's capacitatea de a face cu regex grupe:

> var="someletters_12345_moreletters.ext"
> digits=$( echo $var | sed "s/.*_\([0-9]\+\).*/\1/p" -n )
> echo $digits
12345

Un pic mai general opțiune ar fi nu să presupunem că aveți un caracter de subliniere _ marcajul de început al tău cifre secvență, prin urmare, de exemplu, de separare de pe toate non-numerele pe care le obține înainte de secvența: s/[^0-9]+([0-9]+).*/\1/p`.


> man sed | grep s/regexp/replacement -A 2
s/regexp/replacement/
    Attempt to match regexp against the pattern space.  If successful, replace that portion matched with replacement.  The replacement may contain the special  character  &  to
    refer to that portion of the pattern space which matched, and the special escapes \1 through \9 to refer to the corresponding matching sub-expressions in the regexp.

Mai mult, în cazul în te're nu sunt prea increzator cu regexps:

  • "s" este pentru _s_ubstitute
  • `[0-9]+ meciuri 1+ cifre
  • \1 link-uri către grupul n.1 din regex ieșire (grupa 0 este tot meciul, grupa 1, este un meci între paranteze, în acest caz)
  • "p" steagul este pentru _p_rinting

Toate scapă \ sunt acolo pentru a face sed's regexp de procesare.

Comentarii (0)

Dat test.txt este un fișier care conține "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

cut -b19-20 test.txt > test1.txt # This will extract chars 19 & 20 "ST" 
while read -r; do;
> x=$REPLY
> done < test1.txt
echo $x
ST
Comentarii (1)

Răspunsul meu va avea mai mult control asupra a ceea ce vrei sa iesi din șir. Aici este codul de pe modul în care puteți extrage 12345 din șir

str="someletters_12345_moreleters.ext"
str=${str#*_}
str=${str%_more*}
echo $str

Acest lucru va fi mai eficientă dacă doriți pentru a extrage ceva care are caractere de genul " abc " sau orice caractere speciale cum ar fi _ sau -. De exemplu: Dacă șirul este ca asta si vrei tot ce e după someletters_ și înainte de_moreleters.ext` :

str="someletters_123-45-24a&13b-1_moreleters.ext"

Cu codul meu puteți menționa exact ceea ce vrei. Explicație:

#* Se va elimina precedent string, inclusiv de potrivire cheie. Aici cheia am menționat este _ % Se va elimina următorul șir inclusiv de potrivire cheie. Aici cheia am menționat este '_more*'

Face unele experimente tine și te-ar găsi interesant.

Comentarii (0)

Ok, aici merge pur Parametru de Substituție cu un șir gol. Avertismentul este că am definit someletters și moreletters ca numai caractere. Dacă acestea sunt alfanumerice, acest lucru nu va funcționa așa cum este.

filename=someletters_12345_moreletters.ext
substring=${filename//@(+([a-z])_|_+([a-z]).*)}
echo $substring
12345
Comentarii (1)

similar cu substr('abcdefg', 2-1, 3) in php:

echo 'abcdefg'|tail -c +2|head -c 3
Comentarii (1)

Un bash soluție:


IFS="_" read -r x digs x 
Comentarii (0)

Un pic mai târziu, dar tocmai am dat peste această problemă și a constatat următoarele:

host:/tmp$ asd=someletters_12345_moreleters.ext 
host:/tmp$ echo `expr $asd : '.*_\(.*\)_'`
12345
host:/tmp$ 

Am folosit-o pentru a obține milisecundă rezoluție privind un sistem încorporat care nu au %N pentru data de:

set `grep "now at" /proc/timer_list`
nano=$3
fraction=`expr $nano : '.*\(...\)......'`
$debug nano is $nano, fraction is $fraction
Comentarii (0)

Nu's, de asemenea, bash interna 'expr' comanda:

INPUT="someletters_12345_moreleters.ext"  
SUBSTRING=`expr match "$INPUT" '.*_\([[:digit:]]*\)_.*' `  
echo $SUBSTRING
Comentarii (2)