从URL中提取文件名和路径在bash脚本(Extract filename and path fro

2019-07-31 01:00发布

在我的bash脚本,我需要从给定的URL中提取人的路。 例如,从包含的字符串变量:

HTTP://登录:password@example.com/one/more/dir/file.exe一个=某物&B =某物

我想提取到只有一些其他的变量:

/one/more/dir/file.exe

部分。 当然,登录名,密码,文件名和参数都是可选的。

由于我是新来的sed和awk我向你求助。 请咨询我如何去做。 谢谢!

Answer 1:

在bash:

URL='http://login:password@example.com/one/more/dir/file.exe?a=sth&b=sth'
URL_NOPRO=${URL:7}
URL_REL=${URL_NOPRO#*/}
echo "/${URL_REL%%\?*}"

工作仅在网址开头http://或相同长度的协议,否则,它可能更容易使用正则表达式与sedgrepcut ...



Answer 2:

有在bash内置函数来处理这个问题,例如,字符串模式匹配运算符:

  1. “#”删除最小匹配前缀
  2. “##”除去最大匹配前缀
  3. “%”除去最小匹配后缀
  4. “%%”除去最大匹配后缀

例如:

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命令,编辑器和马克·G·索贝尔Shell编程(http://www.sobell.com/)



Answer 3:

它使用bash如这样做的另一种方式。 它的丑陋,但它的工作原理(至少例子)。 有时候,我喜欢用我称之为筛子削减,我实际上是寻找的信息。

注:在性能方面,这可能是一个问题。

鉴于这些注意事项:

首先,让我们回显行:

echo 'http://login:password@example.com/one/more/dir/file.exe?a=sth&b=sth'

这给了我们:

HTTP://登录:password@example.com/one/more/dir/file.exe一个=某物&B =某物

然后让我们切入线在@作为剥离出一个便捷的方式HTTP://账号:密码

echo 'http://login:password@example.com/one/more/dir/file.exe?a=sth&b=sth' | \
cut -d@ -f2

这给了我们这样的:

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

为了摆脱主机名的,让我们做一次切割并使用/作为分隔符同时要求削减给予我们的第二场,一切之后(主要是,到该行的结束)。 它看起来像这样:

echo 'http://login:password@example.com/one/more/dir/file.exe?a=sth&b=sth' | \
cut -d@ -f2 | \
cut -d/ -f2-

这反过来又导致:

一个/多个/目录/的file.exe?A =某物&B =某物

最后,我们要去掉从终端的所有参数。 同样,我们将使用这个时候 作为分隔符,并告诉它给我们提供了第一个字段。 这给我们带来了结束,如下所示:

echo 'http://login:password@example.com/one/more/dir/file.exe?a=sth&b=sth' | \
cut -d@ -f2 | \
cut -d/ -f2- | \
cut -d? -f1

而输出是:

一个/多个/目录/的file.exe

只是另一种方式来做到这一点,这种做法是一种方式以削减掉的数据,你不需要互动的方式,拿出一些你确实需要。

如果我想塞进一个脚本中的变量这一点,我会做这样的事情:

#!/bin/bash

url="http://login:password@example.com/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}

希望能帮助到你。



Answer 4:

呆子

echo "http://login:password@example.com/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


Answer 5:

如果你有徒劳无功:

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

要么

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

GNU AWK可以使用正则表达式作为字段分隔符(FS)。



Answer 6:

Perl的片段是好奇的,因为Perl是存在于大多数Linux发行版,非常有用的,但是......它并不完全胜任。 具体而言,有在翻译从UTF-8的URL / URI格式转换成路径的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成了'E'。 是否有一个Linux命令,bash的功能,或Perl脚本,它可以处理这种转变,还是我写一个巨大的一系列的sed字符串替换的? 怎么样的逆变换,从路径到URL / URI?

(跟进)

看着http://search.cpan.org/~gaas/URI-1.54/URI.pm ,我第一次看到as_iri方法,但显然我的Linux缺失(或不适用,不知)。 原来的解决方案是,以取代 - “ - >文件”与“>路径”的一部分。 然后,您可以打破这个再往下使用基本名和目录名等。解决的办法是这样的:

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

奇怪的是,使用“ - >目录”而不是“ - >文件”不提取该目录的一部分:更确切地说,它格式化URI所以它可被用作一个参数的mkdir等。

(进一步的后续)

任何原因线不能缩短到这一点?

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


Answer 7:

最好的办法是找到具有URL解析库中的语言:

url="http://login:password@example.com/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' )


Answer 8:

如何做到这一点?

echo 'http://login:password@example.com/one/more/dir/file.exe?a=sth&b=sth' | \
sed 's|.*://[^/]*/\([^?]*\)?.*|/\1|g'
  • :// [^ /] /: HTTP://登录:password@example.com/
  • (* [^]):一个/多个/目录/的file.exe
  • ??*:A =&某物B =某物
  • / \ 1:/one/more/dir/file.exe


Answer 9:

我同意,“切”是在命令行上一个奇妙的工具。 然而,更纯粹的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##*,}


Answer 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))?@"
  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
}


Answer 11:

只使用bash的内建的:

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

这样做是:

  1. 去掉前缀*://*/ (所以这将是您的协议和主机名+端口)
  2. 检查,如果我们真的成功移除任何东西 - 如果没有,那么这意味着没有第三个斜杠(假设这是一个结构良好的URL)
  3. 如果没有第三个斜杠,则路径就是/

注:引号实际上没有必要在这里,但我觉得它更容易与他们在阅读



Answer 12:

url="http://login:password@example.com/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

要获取URL的其他部分,请检查: 获得一个URL(正则表达式)的部分 。



Answer 13:

这Perl的一个班轮工作对我来说在命令行上,所以可以被添加到您的脚本。

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

请注意,这个假设总是会有一个“?” 性格你要提取的字符串的结尾。



文章来源: Extract filename and path from URL in bash script
标签: bash url parsing