Bagaimana cara meniadakan tes dengan ekspresi reguler dalam skrip bash?


174

Menggunakan GNU bash (versi 4.0.35 (1) -release (x86_64-suse-linux-gnu), saya ingin meniadakan tes dengan Ekspresi Reguler. Sebagai contoh, saya ingin menambahkan path ke variabel PATH secara kondisional, jika path belum ada, seperti pada:

TEMP=/mnt/silo/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
export PATH

Saya yakin ada sejuta cara untuk melakukan ini, tetapi yang ingin saya ketahui adalah jika kondisional dapat dinegasikan, seperti dalam (yang keliru):

TEMP=/mnt/silo/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
export PATH

Jawaban:


194

Anda sudah benar, cukup beri jarak antara !dan [[sejenisnyaif ! [[


14
Oye vey! Tepat ketika saya dengan aman menghindari kegilaan karakter khusus intergalaksi, saya menemukan diri saya hilang dalam ruang bash (penempatan)! (Aku merasa takut meremas ususku seperti ular sanca.) Terima kasih!
David Rogers

126

Anda juga dapat menempatkan tanda seru di dalam tanda kurung:

if [[ ! $PATH =~ $temp ]]

tetapi Anda harus jangkar pola Anda untuk mengurangi positif palsu:

temp=/mnt/silo/bin
pattern="(^|:)${temp}(:|$)"
if [[ ! "${PATH}" =~ ${pattern} ]]

yang mencari kecocokan di awal atau akhir dengan titik dua sebelum atau sesudahnya (atau keduanya). Saya sarankan menggunakan nama variabel huruf kecil atau campuran sebagai kebiasaan untuk mengurangi kemungkinan tabrakan nama dengan variabel shell.


Ah, terima kasih atas pengingat tentang penahan. Gagasan untuk menggunakan huruf kecil atau nama variabel campuran membingungkan bagi pemula bash, karena saran yang saya lihat sejauh ini adalah menggunakan huruf besar. Saya mengerti maksud Anda, tetapi saya belum melihat cukup contoh bash scripting untuk merasa nyaman menyimpang dari (pemahaman saya tentang) buku masak.
David Rogers

4
@anyoneis mempercayai kami untuk yang satu ini. Penggunaan variabel huruf besar yang ditentukan pengguna harus dihindari. Semua variabel dalam bash diperluas dengan $sehingga tidak ada alasan untuk huruf besar untuk membuatnya menonjol.
SiegeX

Saya menemukan if [[ ! $foo =~ bar ]]lebih aman daripada if ! [[ $foo =~ bar ]], karena membuat lebih mudah untuk memperkenalkan lebih banyak kondisi keif
CTodea

19

cara paling aman adalah dengan meletakkan! untuk negasi regex dalam [[ ]]seperti ini:

if [[ ! ${STR} =~ YOUR_REGEX ]]; then

kalau tidak, mungkin gagal pada sistem tertentu.


9

Ya, Anda dapat meniadakan tes karena SiegeX telah menunjukkan.

Namun Anda tidak boleh menggunakan ekspresi reguler untuk ini - ini bisa gagal jika jalur Anda berisi karakter khusus. Coba ini sebagai gantinya:

[[ ":$PATH:" != *":$1:"* ]]

(Sumber)


1
Alasan lain untuk menggunakan formulir ini adalah bahwa ia tidak akan secara sengaja mencocokkan substring (misal gagal menambahkan "/ bin" ke path karena "/ usr / bin" sudah ada di sana).
Gordon Davisson

Butuh beberapa saat untuk memahami bagaimana titik dua di kiri memberi saya jangkar yang saya inginkan. ide untuk mengurangi pola dengan menambahkan materi ke string yang akan dicari patut diingat. Saya tidak mengerti mengapa karakter khusus di jalur akan mengganggu solusi regex tetapi bukan solusi pola bash. Bisakah Anda memberi saya contoh?
David Rogers

Saya tidak berpikir ini akan bekerja dengan andal dalam semua kasus. Pencocokan Regex di IMHO superior
Felipe Alvarez

5

Saya suka menyederhanakan kode tanpa menggunakan operator kondisional dalam kasus seperti ini:

TEMP=/mnt/silo/bin
[[ ${PATH} =~ ${TEMP} ]] || PATH=$PATH:$TEMP
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.