Buat indeks string dalam bash

14

Bagaimana saya bisa merujuk ke string dengan indeks di sh / bash? Artinya, pada dasarnya membelahnya.

Saya mencoba menghapus 5 karakter nama file. Semua nama memiliki struktur: name_nr_code. Saya mencoba untuk menghapus bit kode 5 alfanumerik. name_nr_selalu 10 karakter.

Apakah ada sesuatu seperti;

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

Pierre B
sumber
5
Mengapa bashmemberi tag jika Anda meminta shsolusi?
Stéphane Chazelas

Jawaban:

14

Sesederhana ini.

(pesta)

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

Voila.

Dan penjelasan dari Advanced Bash-Scripting Guide ( Bab 10. Memanipulasi Variabel ) , (dengan tambahan NOTEsebaris untuk menyoroti kesalahan dalam manual itu):

Ekstraksi Substring

${string:position}

Ekstrak substring dari $stringpada $position.

Jika $stringparameternya "*" atau "@", maka ini mengekstrak parameter posisi, mulai dari $position.

${string:position:length}

Ekstrak $lengthkarakter substring dari $stringpada $position.

NOTEkutipan yang hilang di sekitar ekspansi parameter! echotidak boleh digunakan untuk data sewenang-wenang.

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.

The posisi dan panjang argumen dapat "diparameterisasi," yaitu, direpresentasikan sebagai variabel, daripada sebagai konstan numerik.


Jika $stringparameternya "*" atau "@", maka ini akan mengekstrak maksimum $lengthparameter posisi, mulai dari $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 substradalah ekstensi GNU.

expr substr $string $position $length

Ekstrak $lengthkarakter $stringmulai dari $position.

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

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

NOTE: Itu echoberlebihan dan membuatnya bahkan kurang dapat diandalkan. Gunakan expr substr + "$string1" 1 2.

NOTE: exprakan kembali dengan status keluar non-nol jika outputnya 0 (atau -0, 00 ...).


BTW. Buku ini hadir dalam repositori resmi Ubuntu sebagai abs-guide.

tomas
sumber
Mengatakan "posisi" sedikit menyesatkan karena sebenarnya merupakan offset, yang berarti ${var:1}tidak mengembalikan nilai dari var"posisi pertama", tetapi sebenarnya dari posisi kedua.
Kusalananda
Itu benar, tetapi selama Anda tidak setuju akan ada posisi ke-nol. Tidak masalah dengan saya.
9

Dalam POSIX sh,

  • "${var%?????}"adalah $vardilucuti dari 5 karakter membuntuti terakhir (atau $varjika $varmengandung kurang dari 5 karakter)

  • "${var%"${var#??????????}"}"adalah 10 karakter pertama dari $var.

  • "${var%_*}"adalah $vardilucuti dari string terpendek yang cocok _*pada akhir $var( foo_bar_baz-> foo_bar).
  • "${var%%_*}": pertandingan yang sama tetapi yang terpanjang dan bukan yang terpendek ( foo_bar_baz-> foo).
  • jika Anda ingin mendapatkan foo_bar_: "${var%"${var##*_}"}"( ${var##pattern}sama seperti ${var%%pattern}tetapi mencari pola di awal, $varbukan di akhir).

Dengan zsh:

  • $var[1,-6] untuk karakter pertama ke 6 dari akhir (jadi semuanya kecuali 5 terakhir).
  • $var[1,10] untuk 10 karakter pertama.

Dengan ksh, bashatau zsh:

  • "${var:0:10}": 10 karakter pertama dari $var

Dengan bashatau zsh:

  • "${var:0:-5}": all kecuali 5 karakter terakhir (memberikan kesalahan dan keluar dari skrip jika $vardiset tetapi berisi kurang dari 5 karakter, juga saat $vartidak diatur dengan zsh).

Jika Anda memerlukan shkompatibilitas Bourne , sangat sulit dilakukan dengan andal. Jika Anda dapat menjamin hasilnya tidak akan berakhir dalam karakter baris baru yang dapat Anda lakukan:

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

Anda juga akan memiliki batas panjang $var(bervariasi antar sistem).

Dalam semua solusi itu, jika $varberisi byte yang tidak dapat membentuk bagian dari karakter yang valid, YMMV.

Stéphane Chazelas
sumber
Ya, mereka benar-benar menghasilkan sintaks yang jelek untuk di dalam kawat gigi itu.
kucing
2

shtidak menyediakan cara bawaan untuk mengeluarkan substring dari string (sejauh yang saya bisa lihat), tetapi dengan bashAnda dapat melakukannya

${i:0:10}

Ini akan memberi Anda sepuluh karakter pertama dari nilai variabel i.

Format umum adalah ${variable:offset:length}.

Kusalananda
sumber
2

Sebagian besar cangkang mendukung beberapa jenis perluasan parameter yang dapat membantu Anda. Di bash, Anda bisa menggunakan

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

Di dash, offset tidak didukung, tetapi Anda dapat menggunakan pola awal dan akhir:

remove_first3=${string#???}
remove_last2=${string%??}
choroba
sumber
0

Pertama, jangan gunakan forloop untuk nama file.

Maka, sesuatu seperti ini akan membantu.

find ./ -type f | while read filename ;do
  newfilename=$(echo ${filename}|cut -c 1-10)
  mv ${filename} ${newfilename}
done
MelBurslan
sumber
3
Mengapa buruk menggunakan fornama file?
choroba
Kutip variabel Anda dan gunakan printfuntuk menjadi lebih aman. ... dan read -r.
Kusalananda
3
forLingkaran OP baik-baik saja kecuali mungkin untuk yang hilang --. Saya dapat melihat setidaknya 10 bug dalam 4 baris kode Anda! banyak di antaranya praktik buruk yang terkenal seperti menganggap nama file adalah satu baris, gunakan gema, kutipan yang hilang
Stéphane Chazelas