Wir können die Syntax verwenden ${var##pattern}
und ${var%%pattern}
den letzten und ersten Abschnitt einer IPv4-Adresse extrahieren:
IP=109.96.77.15
echo IP: $IP
echo 'Extract the first section using ${var%%pattern}: ' ${IP%%.*}
echo 'Extract the last section using ${var##pattern}: ' ${IP##*.}
Wie können wir den zweiten oder dritten Abschnitt einer IPv4-Adresse mithilfe der Parametererweiterung extrahieren?
Hier ist meine Lösung: Ich verwende ein Array und ändere die IFS-Variable.
:~/bin$ IP=109.96.77.15
:~/bin$ IFS=. read -a ArrIP<<<"$IP"
:~/bin$ echo ${ArrIP[1]}
96
:~/bin$ printf "%s\n" "${ArrIP[@]}"
109
96
77
15
Ich habe auch einige Lösungen mit den geschrieben awk
, sed
und cut
Befehlen.
Meine Frage lautet nun: Gibt es eine einfachere Lösung basierend auf der Parametererweiterung, bei der keine Array- und IFS-Änderungen verwendet werden?
IFS
für dieread
dortIFS=. read -a ArrIP<<<"$IP"
IFS=. read a b c d <<< "$IP"
nicht akzeptabel ist (wenn Sie Bash verwenden)? Warum muss es mit Parametererweiterung gemacht werden?Antworten:
Unter der Annahme des Standardwerts von IFS extrahieren Sie jedes Oktett in eine eigene Variable mit:
Oder in ein Array mit:
quelle
Ihre Problemstellung ist möglicherweise etwas liberaler als beabsichtigt. Auf die Gefahr hin, eine Lücke auszunutzen, ist hier die Lösung, auf die muru anspielt :
Das ist etwas klobig. Es definiert zwei Wegwerfvariablen und ist nicht ohne weiteres für die Verarbeitung weiterer Abschnitte geeignet (z. B. für eine MAC- oder IPv6-Adresse). Die Antwort von Sergiy Kolodyazhnyy hat mich dazu inspiriert, Folgendes zu verallgemeinern:
Diese Sätze
sec1
,sec2
,sec3
undsec4
, die mit werden kann verifiziertwhile
Schleife sollte leicht zu verstehen sein - sie wird viermal wiederholt.slice
als Namen für eine Variable, die den Platz vonlast3
undlast2
in meiner ersten Lösung (oben) einnimmt .declare sec"$count"="value"
ist ein Weg , um zuzuordnensec1
,sec2
,sec3
undsec4
wenncount
ist1
,2
,3
und4
. Es ist ein bisschen wieeval
, aber sicherer.value
,"${slice%%.*}"
ist analog zu dem meine ursprünglichen Antwort Werte zugewiesenfirst
,second
undthird
.quelle
Mir ist klar, dass Sie speziell nach einer Lösung gefragt haben, die NICHT vorübergehend neu definiert wurde
IFS
, aber ich habe eine süße und einfache Lösung, die Sie nicht behandelt haben.Der kurze Befehl , um die Elemente Ihrer IP - Adresse in der Shell gesetzt wird Positionsparameter
$1
,$2
,$3
,$4
. Wahrscheinlich möchten Sie jedoch zuerst das Original speichernIFS
und anschließend wiederherstellen.Wer weiß? Vielleicht überdenken und akzeptieren Sie diese Antwort für ihre Kürze und Effizienz.
(Dies wurde zuvor fälschlicherweise als angegeben
IFS=. set -- $IP
)quelle
IFS
in derselben Befehlszeile ändern , wird der neue Wert nicht wirksam, wenn Variablen in derselben Befehlszeile erweitert werden. Gleich wie mitx=1; x=2 echo $x
set
überhaupt nicht verwendet$IFS
,$IFS
wird nur für die Wortaufteilung von verwendet$IP
, aber hier wird es zu spät zugewiesen, so dass dies keine Auswirkung hat. Diese Antwort ist grundsätzlich falsch.IP=109.96.77.15 bash -c 'IFS=. set -- $IP; echo "$2"'
gibt nichts aus, ob im POSIX-Modus oder nicht. Sie würden brauchenIFS=. command eval 'set -- $IP'
, oderIFS=. read a b c d << "$IP"
.
in einem Ihrer vorherigen Tests eingestellt hatten. LaufenIP=1.2.3.4 bash -xc 'IFS=. set $IP; echo "$2"'
Sie und Sie werden sehen, dass es nicht funktioniert. Und sehen SieIP=1.2.3.4 bash -o posix -xc 'IFS=. set $IP; echo "\$1=$1 \$2=$2 IFS=$IFS"'
, um @ chepners Punkt zu veranschaulichen.Nicht die einfachste , aber Sie könnten so etwas tun:
Das sollte in ksh93 arbeiten (wo die
${var//pattern/replacement}
Betreiber herkommt),bash
4.3+, Busyboxsh
,yash
,mksh
undzsh
, obwohl natürlich inzsh
, gibt es viel einfachere Ansätze . In älteren Versionen vonbash
müssten Sie die inneren Anführungszeichen entfernen. Es funktioniert mit den inneren Anführungszeichen, die auch in den meisten anderen Shells entfernt wurden, jedoch nicht mit ksh93.Dies setzt voraus, dass
$IP
eine gültige Quad-Dezimal-Darstellung einer IPv4-Adresse enthalten ist (obwohl dies auch für Quad-Hexadezimal-Darstellungen wie0x6d.0x60.0x4d.0xf
(und in einigen Shells sogar oktal) funktionieren würde, die Werte jedoch dezimal ausgeben würde). Wenn der Inhalt von$IP
aus einer nicht vertrauenswürdigen Quelle stammt, würde dies eine Sicherheitsanfälligkeit bezüglich Befehlsinjektion darstellen.Im Grunde genommen , wie wir alle sind zu ersetzen
.
in$IP
mit+256*(
, wir Auswertung am Ende:Also haben wir ein 32 - Bit - Integer aus diesem 4 Bytes wie eine IPv4 - Adresse sind die Konstruktion ist schließlich (wenn auch mit den Bytes umgekehrt) ¹ und dann mit den
>>
,&
Bitoperatoren das relevante Bytes zu extrahieren.Wir verwenden den
${param+value}
Standardoperator (hier$-
wird immer festgelegt), anstatt nur,value
weil sich der arithmetische Parser sonst über nicht übereinstimmende Klammern beschweren würde. Die Shell hier kann den Abschluss))
für die Öffnung$((
finden und dann die Erweiterungen im Inneren ausführen, die dazu führen, dass der arithmetische Ausdruck ausgewertet wird.Mit
stattdessen behandeln würde die Schale der zweiten und dritten$(((${IP//./"+256*("}))))&255))
)
s dort als Schließ))
für$((
und einen Syntaxfehler melden.In ksh93 können Sie auch Folgendes tun:
bash
,mksh
,zsh
Haben ksh93 des kopierten${var/pattern/replacement}
Betreiber aber nicht , dass der Fang-Gruppe einen Teil der Handhabung.zsh
unterstützt es mit einer anderen Syntax:bash
unterstützt eine Form der Erfassung von Erfassungsgruppen in seinem Regexp-Matching-Operator , jedoch nicht in${var/pattern/replacement}
.POSIXly würden Sie verwenden:
Die
noglob
vermeiden böse Überraschungen für Werte$IP
wie10.*.*.*
die Subshell den Umfang dieser Änderungen an Optionen zu begrenzen und$IFS
.¹ Eine IPv4-Adresse ist nur eine 32-Bit-Ganzzahl und 127.0.0.1 ist beispielsweise nur eine von vielen (wenn auch am häufigsten verwendeten) Textdarstellungen. Dieselbe typische IPv4-Adresse der Loopback-Schnittstelle kann auch als 0x7f000001 oder 127.1 (hier möglicherweise besser geeignet, um zu sagen, dass es sich um die
1
Adresse im 127.0 / 8-Klasse-A-Netzwerk handelt) oder 0177.0.1 oder die anderen Kombinationen von 1 dargestellt werden bis 4 Zahlen ausgedrückt als Oktal, Dezimal oder Hexadezimal. Sie können all diese zumping
Beispiel an übergeben und Sie werden sehen, dass sie alle localhost pingen.Wenn Ihnen der Nebeneffekt des Festlegens einer beliebigen temporären Variablen (hier
$n
) inbash
oderksh93
oderzsh -o octalzeroes
oder nichts ausmachtlksh -o posix
, können Sie einfach alle diese Darstellungen zurück in eine 32-Bit-Ganzzahl konvertieren mit:Und dann extrahieren Sie alle Komponenten mit
>>
/&
Kombinationen wie oben.mksh
verwendet vorzeichenbehaftete 32-Bit-Ganzzahlen für seine arithmetischen Ausdrücke. Dort können Sie$((# n=32,...))
die Verwendung vorzeichenloser 32-Bit-Zahlen erzwingen (und dieposix
Option, Oktalkonstanten zu erkennen).quelle
${-+
. Ich kann auch keine Dokumentation dazu finden. Es funktioniert, aber ich bin nur neugierig zu bestätigen, ob es nur darum geht, die Zeichenfolge in einen mathematischen Ausdruck umzuwandeln. Wo finde ich die formale Definition? Außerdem funktionieren die zusätzlichen Anführungszeichen im Abschnitt zum Ersetzen der Parametererweiterung in GNU bash, Version 4.1.2 (2) - Release CentOS 6.6 nicht. Ich musste das stattdessen tunecho "$((${-+"(${IP//./+256*(}))))"}>>16&255))"
Mit zsh können Sie Parametersubstitutionen verschachteln:
Dies ist in Bash nicht möglich.
quelle
zsh
, können Sie bevorzugen${${(s(.))ip}[3]}
Klar, lass uns das Elefantenspiel spielen.
oder
quelle
Mit
IP=12.34.56.78
.Und
Beschreibung:
Verwendung der Parametererweiterung
${IP// }
, um jeden Punkt in der IP in eine öffnende Klammer, einen Punkt und eine schließende Klammer umzuwandeln. Wenn wir eine anfängliche Klammer und eine schließende Klammer hinzufügen, erhalten wir:Dadurch werden vier Erfassungsklammern für die Regex-Übereinstimmung in der Testsyntax erstellt:
Dies ermöglicht das Drucken des Arrays BASH_REMATCH ohne die erste Komponente (die gesamte Regex-Übereinstimmung):
Die Anzahl der Klammern wird automatisch an die übereinstimmende Zeichenfolge angepasst. Dies entspricht also entweder einem MAC oder einem EUI-64 einer IPv6-Adresse, obwohl diese unterschiedlich lang sind:
Es benutzen:
quelle
Hier ist eine kleine Lösung, die mit POSIX
/bin/sh
(in meinem Falldash
) erstellt wurde, einer Funktion, die wiederholt die Parametererweiterung (alsoIFS
hier nicht) und benannte Pipes verwendet undnoglob
aus den in Stephanes Antwort genannten Gründen eine Option enthält .Das funktioniert so:
Und mit
ip
geändert zu109.*.*.*
Der Schleifenzähler von 4 Iterationen berücksichtigt 4 Abschnitte einer gültigen IPv4-Adresse, während die Akrobatik mit Named Pipes die Notwendigkeit berücksichtigt, Abschnitte der IP-Adresse innerhalb des Skripts weiter zu verwenden, anstatt Variablen in einer Unterschale einer Schleife festzuhalten.
quelle
Warum nicht eine einfache Lösung mit awk verwenden?
$ IP="192.168.1.1" $ echo $IP | awk -F '.' '{ print $1" "$2" "$3" "$4;}'
Ergebnis
$ 192 168 1 1
quelle
quelle