私のbashスクリプトでは、指定されたURLからパスのみを抽出する必要があります。たとえば、文字列を含む変数から:
http:// login:[email protected]/one/more/dir/file.exe?a = sth&b = sth
私は他の変数に抽出したいだけです:
/one/more/dir/file.exe
部。もちろん、ログイン、パスワード、ファイル名、パラメータはオプションです。
私はsedとawkが初めてなので、手助けを求めます。方法を教えてください。ありがとうございました!
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
...で正規表現を使用する方が簡単です。
これを処理するための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
優れた本からのこれらすべて: "Mark G. SobellによるLinuxコマンド、エディター、およびシェルプログラミングの実践ガイド(http://www.sobell.com/)
これは別の方法としてbashとcutを使用します。醜いですが、機能します(少なくとも例では)。時々、私は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
次に、cutの行を@で削除し、便利な方法でストリップしますhttp:// login:password:
echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
cut -d@ -f2
それは私たちにこれを与えます:
example.com/one/more/dir/file.exe?a=sth&b=sth
ホスト名を取り除くには、別のcutを実行して/区切りとして、2番目のフィールド以降のすべてを(基本的には行の終わりまで)提供するようにカットに要求します。次のようになります。
echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
cut -d@ -f2 | \
cut -d/ -f2-
これにより、次の結果になります。
one/more/dir/file.exe?a = sth&b = sth
最後に、最後からすべてのパラメーターを取り除きます。繰り返しますが、cutを使用し、今回は?を区切り文字を使用して、最初のフィールドのみを提供するように指示します。これで終わりになり、次のようになります。
echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
cut -d@ -f2 | \
cut -d/ -f2- | \
cut -d? -f1
そして出力は:
one/more/dir/file.exe
それを行うもう1つの方法であり、このアプローチは、必要のないデータをインタラクティブな方法で作成するために、不要なデータをインタラクティブに取り除く1つの方法です。
これをスクリプトの変数に入れたい場合は、次のようにします。
#!/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}
それが役に立てば幸い。
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
URLの他の部分を取得するには、次を確認してください: RLの一部を取得(正規表現) 。
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スクリプトはありますか?または、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' )
奇妙なことに、「-> file」の代わりに「-> dir」を使用してもディレクトリ部分は抽出されません。むしろ、mkdirなどの引数として使用できるようにURIをフォーマットします。
(さらなるフォローアップ)
行をこれに短縮できない理由は何ですか?
path=$( echo "$url" | Perl -MURI -le 'print URI->new(<>)->file' )
ガウク
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
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)として正規表現を使用できます。
これはどうですか?
echo 'http://login:[email protected]/one/more/dir/file.exe?a=sth&b=sth' | \
sed 's|.*://[^/]*/\([^?]*\)?.*|/\1|g'
Bashビルトインのみを使用:
path="/${url#*://*/}" && [[ "/${url}" == "${path}" ]] && path="/"
これは何ですか:
*://*/
を削除します(これがプロトコルとホスト名+ポートになります)/
になります。注:引用符は実際にはここでは必要ありませんが、一緒に読むと簡単です
最善の策は、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' )
任意の部分または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
}
「カット」はコマンドラインのすばらしいツールであることに同意します。ただし、より純粋な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##*,}