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
David Rogers
sumber

Jawaban:

194

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

SiegeX
sumber
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.

Dijeda sampai pemberitahuan lebih lanjut.
sumber
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.

bukan urusanmu
sumber
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)

Mark Byers
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
dimir
sumber