Подтвердить что ты не робот

Извлечь имя файла и путь из URL-адреса в bash script

В моем bash script мне нужно извлечь только путь из заданного URL. Например, из переменной, содержащей строку:

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

Я хочу извлечь другую переменную только:

/one/more/dir/file.exe

часть. Конечно, логин, пароль, имя файла и параметры являются необязательными.

Поскольку я новичок в sed и awk, я прошу вас о помощи. Пожалуйста, советую мне, как это сделать. Спасибо!

4b9b3361

Ответ 1

В 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%%\?*}"

Работает только в том случае, если URL начинается с http:// или протокола с одинаковой длиной В противном случае, возможно, проще использовать регулярное выражение с sed, grep или cut...

Ответ 2

В bash есть встроенные функции для управления этим, например, операторы сопоставления строк:

  • '#' удалить минимальные совпадающие префиксы
  • '##' удалить максимальные совпадающие префиксы
  • '%' удалить минимальные суффиксы соответствия
  • '%%' удалить максимальные суффиксы соответствия

Например:

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

Все это из превосходной книги: "Практическое руководство по командам, редакторам и оболочке Linux от Mark G. Sobell (http://www.sobell.com/)

Ответ 3

В качестве другого способа использования bash и вырезать используется . Это уродливо, но оно работает (по крайней мере, для примера). Иногда мне нравится использовать то, что я называю cut ситами, чтобы уничтожить информацию, которую я действительно ищу.

Примечание. Производительность, это может быть проблемой.

Учитывая эти оговорки:

Сначала дайте эхо строке:

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

Что дает нам:

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

Затем пусть вырежьте строку на @ как удобный способ вырезать http://login:password:

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

Это дает нам следующее:

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

Чтобы избавиться от имени хоста, сделайте еще один вырежьте и используйте / в качестве разделителя при запросе разреза, чтобы дать нам второе поле и все после (по существу, до конца строки). Это выглядит так:

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

Что, в свою очередь, приводит к:

один/более/DIR/file.exe а = STH &? Б = STH

И, наконец, мы хотим снять все параметры с конца. Опять же, мы будем использовать вырежьте и на этот раз ? в качестве разделителя и скажем, чтобы он дал нам только первое поле. Это доводит нас до конца и выглядит так:

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

И результат:

один/более/реж/file.exe

Еще один способ сделать это, и этот подход - один из способов избавиться от данных, которые вам не нужны в интерактивном режиме, чтобы придумать то, что вам нужно.

Если бы я хотел записать это в переменную в script, я бы сделал что-то вроде этого:

#!/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}

Надеюсь, что это поможет.

Ответ 4

Gawk

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="/"

Выход

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

Ответ 5

Если у вас есть gawk:

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

или

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

Gnu awk может использовать регулярное выражение как разделители полей (FS).

Ответ 6

Фрагмент Perl интригует, и поскольку Perl присутствует на большинстве дистрибутивов Linux, он очень полезен, но... Он не выполняет эту работу полностью. В частности, существует проблема перевода формата URL/URI из UTF-8 в путь Unicode. Позвольте мне привести пример проблемы. Исходный URI может быть:

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

Соответствующий путь:

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

%20 стал пространством, %C3%A9 стал 'é'. Есть ли команда Linux, функция bash или Perl script, которые могут обрабатывать это преобразование, или мне нужно написать обширную серию подстроек sed? Как насчет обратного преобразования, от пути к URL/URI?

(Последующий)

Глядя на http://search.cpan.org/~gaas/URI-1.54/URI.pm, я впервые увидел метод as_iri, но это, очевидно, отсутствовало в моем Linux (или не применимо, как-то). Оказывается, решение заключается в замене части "- > path" на "- > file". Затем вы можете разбить это ниже, используя basename и dirname и т.д. Таким образом, решение:

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

Как ни странно, использование "- > dir" вместо "- > file" НЕ извлекает часть каталога: скорее, он форматирует URI, поэтому его можно использовать в качестве аргумента для mkdir и т.п.

(Дальнейшее наблюдение)

Любая причина, по которой строка не может быть сокращена до этого?

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

Ответ 7

Лучше всего найти язык, на котором есть библиотека синтаксического анализа 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' )

или

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

Ответ 8

Как это сделать:?

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

Ответ 9

Я согласен, что "cut" - прекрасный инструмент в командной строке. Однако более чисто bash решение заключается в использовании мощной функции расширения переменных в bash. Например:

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##*,}

Ответ 10

Я написал функцию, которая будет извлекать любую часть или URL-адрес. Я тестировал его только в bash. Использование:

url_parse <url> [url-part]

пример:

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

код:

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
}

Ответ 11

Этот однострочный perl работает для меня в командной строке, поэтому его можно добавить в script.

echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | perl -n -e 'm{http://[^/]+(/[^?]+)};print $1'

Обратите внимание, что это предполагает, что всегда будет '?' символ в конце строки, которую вы хотите извлечь.