次のHLSプレイリストファイルがあります。
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:12.500000,
playlist0.ts
#EXTINF:8.333333,
playlist1.ts
#EXTINF:12.500000,
playlist2.ts
....
これには、次のlink()を含むファイルがありますsignurls.txt
。
https://example.com/playlist0.ts?Sign=xyz&Exp=1639139375&AWSAccessKeyId=abc
https://example.com/playlist1.ts?Sign=yzx&Exp=1639139375&AWSAccessKeyId=bca
https://example.com/playlist10.ts?Sign=zyx&Exp=1639139375&AWSAccessKeyId=cab
....
.m3u8
次のファイルにリンクを挿入しようとしています。
....
#EXTINF:12.500000,
https://example.com/playlist0.ts?Sign=xyz&Exp=1639139375&AWSAccessKeyId=abc
....
私はこのスクリプトを思い出しました。
for f in *.ts; do
sed -i '' -e "'s|$f|`grep -e $f signurls.txt`|'" playlist.m3u8;
done
編集する:.ts
fileにリストされている各ファイルはplaylist.m3u8
現在のディレクトリにあります。ループには実際のファイルを使用するので、for
問題なくプレイリストファイルを変更できます。
その理由は、-i ''
macOSとLinuxの両方で実行する必要があるからです。
文字列をエコーしてみるsed
と、文字列拡張が期待どおりに機能することがわかります。
ただし、スクリプトを実行すると、次のエラーが発生します(1行のスクリプト)。
sed: 1: "'s|playlist0.ts|https:/ ...": invalid command code '
答え1
something.ts
コードで明確に使用しているファイルを呼び出すように見えることは無視します。記事にはこの内容について言及していないので分からないふりをします。
$ cat urls
https://example.com/playlist0.ts?Sign=xyz&Exp=1639139375&AWSAccessKeyId=abc
https://example.com/playlist1.ts?Sign=yzx&Exp=1639139375&AWSAccessKeyId=bca
https://example.com/playlist10.ts?Sign=zyx&Exp=1639139375&AWSAccessKeyId=cab
$ cat playlist.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:12.500000,
playlist0.ts
#EXTINF:8.333333,
playlist1.ts
#EXTINF:12.500000,
playlist2.ts
$ awk -F'[/?]' 'NR==FNR { pl[$4]=$0; next } /^[^#]/ && ($0 in pl) { $0 = pl[$0] }; 1' urls playlist.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:12.500000,
https://example.com/playlist0.ts?Sign=xyz&Exp=1639139375&AWSAccessKeyId=abc
#EXTINF:8.333333,
https://example.com/playlist1.ts?Sign=yzx&Exp=1639139375&AWSAccessKeyId=bca
#EXTINF:12.500000,
playlist2.ts
上記のコマンドは最初に最初のawk
ファイル()からURLを読み取り、その文字列を名前付き連想配列にキーとして追加します。完全な URL が配列値として追加されます。urls
.ts
pl
.ts
これらの文字列は、各URLをスラッシュまたは疑問符で区切られた文字列として扱い、その文字列から4番目のフィールドを選択することで見つけることができます。
その後、コードは.m3u8
ファイルから行を読み取り、文字で始まらない各行について、その行が配列のキーであるかどうかを#
テストしますpl
。その場合、現在の行は配列の対応するURLに置き換えられます。.m3u8
次に、ファイルのすべての行を印刷します(今説明したように変更可能)。
上記の例では、プレイリストファイルの最後のエントリは、そのエントリのURLがファイルにないために置き換えられていないことを示していますurls
。
答え2
while
テキストを処理するためにシェルやforを使用しないでくださいloop
。バラよりシェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?理由があります。
代わりに、テキスト処理のためperl
または非シェル言語をawk
使用してください。python
signurls
これは、ファイル-s
を読み取って処理できるようにファイルを指定できるように、Getopt :: Stdモジュール(Perlに含まれるコアライブラリモジュール)を使用するPerlシングルライナーです。それぞれプレイリストファイルから - 私たちが望んでいないので、これは重要ですそれ変更するオプションファイルです-i
。
$signurls = shift;
これは(最初のパラメータ)または(最後のパラメータ)のように実行できますが、$signurls = pop;
a)これはsignurlsファイルを意味します。持つ最初の(または最後の)引数になります(柔軟ではありませんが、速くて汚いハッカーにとって必ずしも悪いわけではありません)。 b)$ signurlsにデフォルトのファイル名を提供することは、より複雑で信頼性が低くなります。 c) 難しくない。これを使用しておりGetopt::Std
、使い方がわかる便利なライブラリモジュールです。
後続のすべてのパラメータはプレイリストファイルとして扱われます。として処理されるため、while(<>)
perlオプションを使用して内部で変更できます-i
。
$ perl -MGetopt::Std -i.bak -lpe '
BEGIN {
# Parse any command line options.
getopts("s:", \%opts);
my $signurls = $opts{s} // "signurls.txt";
# Read in signurls file and build hash containing patterns
# and replacement strings.
open($fh,"<",$signurls) || die "error opening \"$signurls\": $!\n";
while(<$fh>) {
chomp;
# Extract the "filename" portion of the URL and use it as the hash's key.
# the hash's value is the URL itself.
m=^.*://.*?/([^/]*)[/?].*=;
$urls{$1} = $_;
};
close($fh);
};
foreach my $f (keys %urls) {
if ($_ eq $f) {
$_ = $urls{$f};
last; # we already matched, so there's no need to
# compare this line against the remaining keys.
};
};' -s signurls.txt playlist.m3u38
注1:.bak
After-i
は、Perlに各ソース入力(プレイリスト)ファイル名のバックアップコピー(.bak拡張子を含む)を作成させます。
注2:BEGIN { ... }
コードブロックが実行されます。一度ファイルを開いたり処理したりする前。 BEGINブロック外の残りのスクリプトは、入力ファイルの各データ行に対して1回実行されます。
実行後のサンプル出力:
$ cat playlist.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:12.500000,
https://example.com/playlist0.ts?Sign=xyz&Exp=1639139375&AWSAccessKeyId=abc
#EXTINF:8.333333,
https://example.com/playlist1.ts?Sign=yzx&Exp=1639139375&AWSAccessKeyId=bca
#EXTINF:12.500000,
playlist2.ts
私できる-P
プレイリストファイルのオプションを持つように作成しました。実は私が最初にそう書いたんです。ただし、プレイリストを読み取って処理するためにPerlの-p
オプション(自動ループにすぎませんwhile(<>)
- 参考資料を参照)を使用するように作成すると、Perlのオプションを使用でき、スクリプトが直接作成することなくプレイリストファイルをその場で編集できるようになります。できます。内部編集コード。また、追加コードなしで複数の入力ファイルを処理するためのサポートも追加されました。 2つの便利な機能は無料です。man perlrun
-i
答え3
sed
ループで使用
$ while read line; do sed -i.bak "s#$(sed 's#.*/\([^?]*\).*#\1#' <<< $line)#$line#" playlist.m3u8; done < signurls.txt
$ cat playlist.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:12.500000,
https://example.com/playlist0.ts?Sign=xyzplaylist0.tsExp=1639139375playlist0.tsAWSAccessKeyId=abc
#EXTINF:8.333333,
https://example.com/playlist1.ts?Sign=yzxplaylist1.tsExp=1639139375playlist1.tsAWSAccessKeyId=bca
#EXTINF:12.500000,
playlist2.ts
....
答え4
提供されたエラーメッセージは実際に私が思ったよりも良く、実際に文字の'
問題であることがわかりました。
'
パターン文字列から文字を削除するとsed
問題が解決されました。
for f in *.ts; do
sed -i "" "s|$f|$(grep -e $f signurls.txt)|g" playlist.m3u8 ;
done