2010-12-27 18 views
93

Używając GNU bash (wersja 4.0.35 (1) -release (x86_64-suse-linux-gnu), chciałbym zanegować test za pomocą Wyrażeń regularnych. Na przykład, chciałbym warunkowo dodać ścieżkę do PATH zmienna, jeśli ścieżka nie jest już tam, jak w:Jak negować test za pomocą wyrażeń regularnych w skrypcie bash?

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 

Jestem pewien, że istnieje milion sposobów, aby to zrobić, ale to, co chciałbym wiedzieć, czy warunkowe mogą być negowane jakoś, jak w (błędne):

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 

Dzięki

Odpowiedz

98

Trzeba było to w porządku, po prostu umieścić spację między ! i [[ jak if ! [[

+9

Oye vey! Właśnie wtedy, gdy bezpiecznie omijam międzygalaktyczne szaleństwo charakterystyczne dla perla, znajduję się zagubiony w przestrzeni basha (umieszczenie)! (Czuję strach ściskając moje wnętrzności jak pyton.) Dzięki! –

6

Tak, możesz już zanegować test, o czym już wcześniej wspomniała SiegeX.

Jednak nie powinieneś używać do tego wyrażeń regularnych - może się to nie udać, jeśli twoja ścieżka zawiera znaki specjalne. Spróbuj to zamiast:

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

(Source)

+1

Kolejny powód, aby użyć tej postaci, że nie przypadkowo pasujące podciągi (np nie dodać „/ bin” do ścieżka, ponieważ "/ usr/bin" już tam jest). –

+0

Zajęło mi trochę czasu, aby zrozumieć, w jaki sposób dwukropki po lewej dały mi zakotwiczenie, które chciałem. należy pamiętać o idei zmniejszania wzorca poprzez dodawanie materiału do szukanego łańcucha. Nie rozumiem, dlaczego znaki specjalne na ścieżce zakłóciłyby rozwiązanie regex, ale nie rozwiązanie typu bash pattern. Czy możesz podać mi przykład? –

+0

Nie sądzę, że to będzie działać niezawodnie we wszystkich przypadkach. Dopasowanie Regex w lepszym IMHO –

80

Można również umieścić Wykrzyknik wewnątrz nawiasów:

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

ale należy zakotwiczyć swój wzór, aby zmniejszyć liczbę fałszywych trafień:

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

, która szuka dopasowania na początku lub końcu dwukropka przed nim lub po nim (lub obu). Polecam używanie nazw zmiennych pisanych małymi lub małymi literami jako nawyku zmniejszania prawdopodobieństwa kolizji nazw ze zmiennymi powłoki.

+0

Ah, dzięki za przypomnienie o zakotwiczeniu. Pomysł użycia małych lub mieszanych nazw zmiennych jest mylący dla początkującego basha, ponieważ porady, które widziałem do tej pory, używają wielkich liter. Rozumiem, co robisz, ale nie widziałem wystarczająco dużo przykładów skryptów bash, aby czuć się komfortowo odejście od (mojego zrozumienia) książki kucharskiej. –

+3

@anyoneis zaufaj nam w tej sprawie.Należy unikać stosowania zmiennych pisanych wielką literą definiowanych przez użytkownika. Wszystkie zmienne w bashu są rozszerzane o '$', więc nie ma powodu, aby je pisać dużymi literami, aby je wyróżnić. – SiegeX

+0

Znajduję 'if [[! $ foo = ~ bar]] 'bezpieczniejsze niż' jeśli! [[$ foo = ~ bar]] ', ponieważ ułatwia wprowadzenie dodatkowych warunków do' if' – CTodea

15

najbezpieczniejszym sposobem jest umieszczenie! dla regex negacji w [[ ]] jak ten:

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

inaczej może nie działać na niektórych systemach.

0

Lubię uproszczenie kodu bez użycia operatorów warunkowych w takich przypadkach:

TEMP=/mnt/silo/bin 
[[ ${PATH} =~ ${TEMP} ]] || PATH=$PATH:$TEMP