Dans mon script bash, je n'ai besoin d'extraire que le chemin de l'URL donnée ... Par exemple, à partir de la variable contenant la chaîne:
http: // login: [email protected]/one/more/dir/file.exe? a = sth & b = sth
Je veux extraire à une autre variable que le:
/one/more/dir/file.exe
partie. Bien sûr, login, mot de passe, nom de fichier et paramètres sont facultatifs.
Depuis que je suis nouveau à sed et awk je vous demande de l'aide. S'il vous plaît, conseillez-moi comment le faire. Je vous remercie!
En 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%%\?*}"
Fonctionne uniquement si l'URL commence par http://
ou un protocole de même longueur Sinon, il est probablement plus facile d'utiliser regex avec sed
, grep
ou cut
.
Bash contient des fonctions intégrées pour gérer cela, par exemple, les opérateurs de correspondance de modèle de chaîne:
Par exemple:
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
Tout cela dans l'excellent livre "Un guide pratique sur les commandes, les éditeurs et la programmation shell sous Linux" de Mark G. Sobell (http://www.sobell.com/)
Ceci utilise bash et cut comme un autre moyen de le faire. C'est moche, mais ça marche (du moins pour l'exemple). Parfois, j'aime utiliser ce que j'appelle des tamis couper pour réduire l'information que je recherche réellement.
Remarque: Performance sage, cela peut être un problème.
Compte tenu de ces mises en garde:
D'abord, faisons écho à la ligne:
echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth'
Ce qui nous donne:
http: // login: [email protected]/one/more/dir/file.exe? a = sth & b = sth
Puis, coupons la ligne située au @ comme un moyen pratique de supprimer les http: // login: mot de passe:
echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
cut -d@ -f2
Cela nous donne ceci:
example.com/one/more/dir/file.exe?a=sth&b=sth
Pour supprimer le nom d’hôte, faisons un autre cut et utilisons le / comme délimiteur en demandant à cut de nous donner le deuxième champ et tout ce qui suit (essentiellement, jusqu’à la fin de la ligne). Cela ressemble à ceci:
echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
cut -d@ -f2 | \
cut -d/ -f2-
Ce qui entraîne à son tour:
un/plusieurs/dir/fichier.exe? a = sth & b = sth
Et enfin, nous voulons éliminer tous les paramètres de la fin. Encore une fois, nous allons utiliser cut et cette fois, le ? comme délimiteur et dites-lui de ne nous donner que le premier champ. Cela nous amène à la fin et ressemble à ceci:
echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
cut -d@ -f2 | \
cut -d/ -f2- | \
cut -d? -f1
Et le résultat est:
un/plus/dir/fichier.exe
Une autre façon de le faire et cette approche sont un moyen de réduire de manière interactive les données dont vous n’avez pas besoin de manière interactive pour trouver ce dont vous avez besoin.
Si je voulais insérer cela dans une variable dans un script, je ferais quelque chose comme ceci:
#!/bin/bash
url="http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth"
file_path=$(echo ${url} | cut -d@ -f2 | cut -d/ -f2- | cut -d? -f1)
echo ${file_path}
J'espère que ça aide.
Le fragment de code Perl est intriguant et, comme Perl est présent dans la plupart des distributions Linux, il est très utile, mais ... Il ne fait pas le travail complètement. Plus précisément, la traduction du format d'URL/URI d'UTF-8 en chemin Unicode pose un problème. Permettez-moi de donner un exemple du problème. L'URI d'origine peut être:
file:///home/username/Music/Jean-Michel%20Jarre/M%C3%A9tamorphoses/01%20-%20Je%20me%20souviens.mp3
Le chemin correspondant serait:
/home/username/Music/Jean-Michel Jarre/Métamorphoses/01 - Je me souviens.mp3
%20
est devenu l'espace, %C3%A9
est devenu 'é'. Existe-t-il une commande Linux, une fonctionnalité bash ou un script Perl capable de gérer cette transformation, ou dois-je écrire une énorme série de substitutions de sous-chaînes sed? Qu'en est-il de la transformation inverse, du chemin d'accès à l'URL/URI?
(Suivre)
En regardant http://search.cpan.org/~gaas/URI-1.54/URI.pm , j'ai d'abord vu la méthode as_iri, mais cela manquait apparemment dans mon Linux (ou n'est pas applicable, en quelque sorte) . Il s'avère que la solution consiste à remplacer la partie "-> chemin" par "-> fichier". Vous pouvez ensuite décomposer cela en utilisant basename et dirname, etc. La solution est la suivante:
path=$( echo "$url" | Perl -MURI -le 'chomp($url = <>); print URI->new($url)->file' )
Bizarrement, utiliser "-> dir" au lieu de "-> fichier" n'extrait PAS la partie de répertoire: il formate plutôt l'URI de sorte qu'il puisse être utilisé comme argument de mkdir et autres.
(Suite de suivi)
Une raison pour laquelle la ligne ne peut pas être raccourcie à cela?
path=$( echo "$url" | Perl -MURI -le 'print URI->new(<>)->file' )
rester bouche bée
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="/"
sortie
# ./test.sh
/one/more/dir/file.exe
Si vous avez un gawk:
$ echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
gawk '$0=gensub(/http:\/\/[^/]+(\/[^?]+)\?.*/,"\\1",1)'
ou
$ echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
gawk -F'(http://[^/]+|?)' '$0=$2'
Gnu awk peut utiliser une expression régulière comme séparateur de champs (FS).
Comment ça:?
echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
sed 's|.*://[^/]*/\([^?]*\)?.*|/\1|g'
url="http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth"
grep
$ grep -Po '\w\K/\w+[^?]+' <<<$url
/one/more/dir/file.exe
grep
$ grep -o '\w/\w\+[^?]\+' <<<$url | tail -c+2
/one/more/dir/file.exe
$ rg -o '\w(/\w+[^?]+)' -r '$1' <<<$url
/one/more/dir/file.exe
Pour obtenir d'autres parties d'URL, vérifiez: Obtenir des parties d'une URL (Regex) .
En utilisant uniquement les commandes internes bash:
path="/${url#*://*/}" && [[ "/${url}" == "${path}" ]] && path="/"
Ce que cela fait est:
*://*/
(il s'agirait donc de votre protocole et de votre nom d'hôte + port)/
note: les guillemets ne sont pas vraiment nécessaires ici, mais je trouve plus facile de lire avec eux dans
Le meilleur choix est de trouver une langue disposant d'une bibliothèque d'analyse d'URL
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' )
ou
path=$( echo "$url" | Perl -MURI -le 'chomp($url = <>); print URI->new($url)->path' )
J'ai écrit une fonction pour extraire n'importe quelle partie ou l'URL. Je l'ai seulement testé en bash. Usage:
url_parse <url> [url-part]
exemple:
$ 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))?@"
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
}
Je conviens que "couper" est un outil merveilleux sur la ligne de commande. Cependant, une solution plus purement bash consiste à utiliser une fonctionnalité puissante d’expansion variable dans bash. Par exemple:
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##*,}