webentwicklung-frage-antwort-db.com.de

Extrahieren Sie Dateinamen und Pfad aus der URL im Bash-Skript

In meinem Bash-Skript muss ich nur den Pfad aus der angegebenen URL extrahieren. Zum Beispiel aus der Variable, die den String enthält:

http: // login: [email protected]/one/more/dir/file.exe? a = sth & b = sth

Ich möchte nur eine andere Variable extrahieren:

/one/more/dir/file.exe

teil. Natürlich sind Login, Passwort, Dateiname und Parameter optional.

Da ich neu bei sed und awk bin, bitte ich Sie um Hilfe. Bitte, raten Sie mir, wie es geht. Vielen Dank!

22
Arek

In Bash:

URL='http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth'
URL_NOPRO=${URL:7}
URL_REL=${URL_NOPRO#*/}
echo "/${URL_REL%%\?*}"

Funktioniert nur, wenn die URL mit http:// oder einem Protokoll mit der gleichen Länge Beginnt. Andernfalls ist es wahrscheinlich einfacher, regex mit sed, grep oder cut zu verwenden.

29
saeedgnu

In bash gibt es integrierte Funktionen, um dies zu handhaben, z. B. die Zeichenfolgenanpassungsoperatoren:

  1. '#' entfernt minimale übereinstimmende Präfixe
  2. '##' Entfernen Sie die maximal passenden Präfixe
  3. '%' entfernt minimale übereinstimmende Suffixe
  4. '%%' entfernt die maximal passenden Suffixe

Zum Beispiel:

FILE=/home/user/src/prog.c
echo ${FILE#/*/}  # ==> user/src/prog.c
echo ${FILE##/*/} # ==> prog.c
echo ${FILE%/*}   # ==> /home/user/src
echo ${FILE%%/*}  # ==> nil
echo ${FILE%.c}   # ==> /home/user/src/prog

Dies alles aus dem ausgezeichneten Buch: "Ein praktischer Leitfaden für Linux-Befehle, Editoren und Shell-Programmierung von Mark G. Sobell (http://www.sobell.com/)

71
JESii

Dies verwendet bash und cut als eine andere Möglichkeit, dies zu tun. Es ist hässlich, aber es funktioniert (zumindest für das Beispiel). Manchmal benutze ich gerne das, was ich cut Siebe nenne, um die Informationen, die ich eigentlich suche, zu verfeinern. 

Hinweis: Leistungstechnisch kann dies ein Problem sein.

Unter Berücksichtigung dieser Vorbehalte:

Lassen Sie uns zunächst die Zeile wiederholen:

echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth'

Was gibt uns:

http: // login: [email protected]/one/more/dir/file.exe? a = sth & b = sth

Dann lassen Sie uns cut die Zeile an der @ als bequeme Methode zum Entfernen der http: // login: password:

echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
cut [email protected] -f2

Das gib uns das:

example.com/one/more/dir/file.exe?a=sth&b=sth

Um den Hostnamen loszuwerden, führen wir ein weiteres cut aus und verwenden das/als Trennzeichen, während Sie cut bitten, uns das zweite Feld und alles danach (im Wesentlichen bis zum Ende des Linie). Es sieht aus wie das:

echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
cut [email protected] -f2 | \
cut -d/ -f2-

Was wiederum ergibt:

one/more/dir/file.exe? a = sth & b = sth

Und zum Schluss wollen wir alle Parameter vom Ende entfernen. Wieder verwenden wir cut und diesmal das? als Trennzeichen und teilen Sie uns mit, dass Sie nur das erste Feld angeben müssen. Das bringt uns zum Ende und sieht so aus:

echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
cut [email protected] -f2 | \
cut -d/ -f2- | \
cut -d? -f1

Und die Ausgabe ist:

one/more/dir/file.exe

Eine andere Möglichkeit, dies zu tun, und dieser Ansatz ist eine Möglichkeit, die Daten, die Sie nicht benötigen, auf interaktive Weise zu entfernen, um etwas zu finden, das Sie benötigen.

Wenn ich das in eine Variable in ein Skript packen wollte, würde ich so etwas tun:

#!/bin/bash

url="http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth"
file_path=$(echo ${url} | cut [email protected] -f2 | cut -d/ -f2- | cut -d? -f1)
echo ${file_path}

Ich hoffe es hilft.

6
Jim

Das Perl-Snippet ist faszinierend, und da Perl in den meisten Linux-Distributionen vorhanden ist, ist es sehr nützlich, aber ... Es erledigt den Job nicht vollständig. Insbesondere beim Konvertieren des URL/URI-Formats von UTF-8 in den Pfad Unicode ist ein Problem aufgetreten. Lassen Sie mich ein Beispiel für das Problem geben. Der ursprüngliche URI kann sein:

file:///home/username/Music/Jean-Michel%20Jarre/M%C3%A9tamorphoses/01%20-%20Je%20me%20souviens.mp3

Der entsprechende Pfad wäre:

/home/username/Music/Jean-Michel Jarre/Métamorphoses/01 - Je me souviens.mp3

%20 wurde zu Leerzeichen, %C3%A9 wurde 'é'. Gibt es einen Linux-Befehl, eine Bash-Funktion oder ein Perl-Skript, die diese Umwandlung abwickeln können, oder muss ich eine umfangreiche Reihe von sed-Unterstringsubstitutionen schreiben? Was ist mit der umgekehrten Umwandlung vom Pfad zu URL/URI?

(Nachverfolgen)

Beim Betrachten von http://search.cpan.org/~gaas/URI-1.54/URI.pm habe ich zuerst die as_iri-Methode gesehen, die aber anscheinend in meinem Linux fehlte (oder ist irgendwie nicht anwendbar). . Es stellt sich heraus, dass die Lösung darin besteht, den Teil "-> Pfad" durch "-> Datei" zu ersetzen. Sie können das weiter unten mit basename und dirname usw. aufteilen. Die Lösung lautet also:

path=$( echo "$url" | Perl -MURI -le 'chomp($url = <>); print URI->new($url)->file' )

Seltsamerweise wird bei der Verwendung von "-> dir" anstelle von "-> file" der Verzeichnisteil NICHT extrahiert. Stattdessen wird der URI so formatiert, dass er als Argument für mkdir und dergleichen verwendet werden kann.

(Weitere Nachbereitung)

Gibt es einen Grund, warum die Zeile nicht so verkürzt werden kann?

path=$( echo "$url" | Perl -MURI -le 'print URI->new(<>)->file' )
2
Urhixidur

gaffen

echo "http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth" | awk -F"/" '
{
 $1=$2=$3=""
 gsub(/\?.*/,"",$NF)
 print substr($0,3)
}' OFS="/"

ausgabe

# ./test.sh
/one/more/dir/file.exe
2
ghostdog74

Wenn Sie einen Gawk haben:

$ echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
  gawk '$0=gensub(/http:\/\/[^/]+(\/[^?]+)\?.*/,"\\1",1)'

oder

$ echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
  gawk -F'(http://[^/]+|?)' '$0=$2'

Gnu awk kann reguläre Ausdrücke als Feldtrennzeichen (FS) verwenden.

2
Hirofumi Saito

Wie funktioniert das?

echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
sed 's|.*://[^/]*/\([^?]*\)?.*|/\1|g'
1
sed
url="http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth"

GNU grep

$ grep -Po '\w\K/\w+[^?]+' <<<$url
/one/more/dir/file.exe

BSD grep

$ grep -o '\w/\w\+[^?]\+' <<<$url | tail -c+2
/one/more/dir/file.exe

ripgrep

$ rg -o '\w(/\w+[^?]+)' -r '$1' <<<$url
/one/more/dir/file.exe

Um andere Teile der URL zu erhalten, überprüfen Sie: Teile einer URL (Regex) abrufen.

1
kenorb

Nur bash builtins verwenden:

path="/${url#*://*/}" && [[ "/${url}" == "${path}" ]] && path="/"

Was das macht, ist:

  1. entferne das Präfix *://*/ (also wäre dies dein Protokoll und Hostname + Port)
  2. Überprüfen Sie, ob wir tatsächlich etwas entfernt haben. Wenn dies nicht der Fall ist, bedeutet dies, dass es keinen dritten Schrägstrich gab (vorausgesetzt, es handelt sich um eine wohlgeformte URL).
  3. wenn es keinen dritten Schrägstrich gab, ist der Pfad nur /

Hinweis: Die Anführungszeichen werden hier eigentlich nicht benötigt, aber ich finde es einfacher, sie mit zu lesen

1
caldfir

Am besten ist es, eine Sprache zu finden, die über eine Bibliothek zur URL-Analyse verfügt:

url="http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth"
path=$( echo "$url" | Ruby -ruri -e 'puts URI.parse(gets.chomp).path' )

oder

path=$( echo "$url" | Perl -MURI -le 'chomp($url = <>); print URI->new($url)->path' )
1
glenn jackman

Ich habe eine Funktion geschrieben, um jeden Teil oder die URL zu extrahieren. Ich habe es nur in bash getestet. Verwendungszweck: 

url_parse <url> [url-part]

beispiel: 

$ url_parse "http://example.com:8080/home/index.html" path
home/index.html

code:

url_parse() {
  local -r url=$1 url_part=$2
  #define url tokens and url regular expression
  local -r protocol='^[^:]+' user='[^:@]+' password='[^@]+' Host='[^:/?#]+' \
    port='[0-9]+' path='\/([^?#]*)' query='\?([^#]+)' fragment='#(.*)'
  local -r auth="($user)(:($password))[email protected]"
  local -r connection="($auth)?($Host)(:($port))?"
  local -r url_regex="($protocol):\/\/($connection)?($path)?($query)?($fragment)?$"
  #parse url and create an array
  IFS=',' read -r -a url_arr <<< $(echo $url | awk -v OFS=, \
    "{match(\$0,/$url_regex/,a);print a[1],a[4],a[6],a[7],a[9],a[11],a[13],a[15]}")

  [[ ${url_arr[0]} ]] || { echo "Invalid URL: $url" >&2 ; return 1 ; }

  case $url_part in
    protocol) echo ${url_arr[0]} ;;
    auth)     echo ${url_arr[1]}:${url_arr[2]} ;; # ex: john.doe:1234
    user)     echo ${url_arr[1]} ;;
    password) echo ${url_arr[2]} ;;
    Host-port)echo ${url_arr[3]}:${url_arr[4]} ;; #ex: example.com:8080
    Host)     echo ${url_arr[3]} ;;
    port)     echo ${url_arr[4]} ;;
    path)     echo ${url_arr[5]} ;;
    query)    echo ${url_arr[6]} ;;
    fragment) echo ${url_arr[7]} ;;
    info)     echo -e "protocol:${url_arr[0]}\nuser:${url_arr[1]}\npassword:${url_arr[2]}\nhost:${url_arr[3]}\nport:${url_arr[4]}\npath:${url_arr[5]}\nquery:${url_arr[6]}\nfragment:${url_arr[7]}";;
    "")       ;; # used to validate url
    *)        echo "Invalid URL part: $url_part" >&2 ; return 1 ;;
  esac
}
1
Mike

Ich stimme zu, dass "Ausschneiden" ein wunderbares Werkzeug in der Befehlszeile ist. Eine reinere bash-Lösung ist jedoch die Verwendung einer leistungsstarken Funktion der variablen Erweiterung in bash. Zum Beispiel:

pass_first_last='password,firstname,lastname'

pass=${pass_first_last%%,*}

first_last=${pass_first_last#*,}

first=${first_last%,*}

last=${first_last#*,}

or, alternatively,

last=${pass_first_last##*,}
1
Roger