バッシュ文字列は複数の文字を1つに置き換えます


8

フィードのタイトルから、文字と数字を除くすべての文字をダッシュ​​に置き換えて、ファイルシステムの安全なファイル名として結果を使用します。

$ t="Episodie 06: No hope of riding home (NEW) - Advanced grammar"
$ echo ${t//[^A-Za-z0-9]/-}
Episodie-06--No-hope-of-riding-home--NEW----Advanced-grammar

しかし、私はすべての繰り返しダッシュを次のように1つに凝縮したいと思います Episodie-06-No-hope-of-riding-home-NEW-Advanced-grammar

私は2パスの置換を使用してそれを達成できることを発見しました:

$ t="Episodie 06: No hope of riding home (NEW) - Advanced grammar"
$ tmp=${t//[^A-Za-z0-9]/-}
$ echo ${tmp//--/-}
Episodie-06-No-hope-of-riding-home-NEW--Advanced-grammar

私は次のような単一のパスでそれを行うことができると思いました:

$ echo ${t//[^A-Za-z0-9]+/-}

しかし、それは機能しません。

どんな手掛かり?

注:sed他のツールと一緒に行きたくない

回答:


8

従来のシェルワイルドカードよりも強力なものが必要です。bashでextglobオプションを設定します。これにより、kshから継承された通常とは異なる構文を使用して、globパターンの正規表現にアクセスできます。

shopt -s extglob
sanitized=${raw//+([^A-Za-z0-9])/-}

おかげで、このソリューションでjw013の回答の下にferedからのコメントがありました。この構文の他のシェルとの互換性に関するいくつかの情報?私はそれについてそれほど心配していませんshopt。それをどのシェルがサポートしているかをもっと知りたいだけです。
ニューリノ

@neurino shoptはbashに固有です。それが有効にするパターン構文は、すべてのkshバリアントで常に利用可能です。zshでは、この構文をで有効にする必要がありますsetopt ksh_glob。POSIXにはそのような機能はありません。ワイルドカードは正規表現ほど強力ではありません。bash / ksh / zsh以外のシェルは、実際にはほとんどが今日の灰を意味し、POSIXワイルドカードを使用する傾向があります。
ジル 'SO-悪をやめる'

さて、この時点で、互換性と柔軟性を優先し、オーバーヘッドを少し増やしますecho "$t" | sed -r 's/[^[:alnum:]]+/-/g; s/^-|-$//'。質問の内容を正確に反映するので、私はあなたの回答を受け入れます。
ニューリノ

@neurino他のシェルへの移植性が必要な場合は、glenn jackmanの回答を使用できます。ちなみに、この${var/PATTERN/REPLACEMENT}構造はksh / bash / zshにも固有であることに注意してください。
Gilles 'SO-悪をやめる'

私はsedその構文と動作をよく知っているので、先頭/末尾のダッシュを削除するステートメントを簡単に追加でき、\nchar を気にする必要はありません。あるsed未満利用可能な方法はtr
ニューリノ

7

tr この仕事に適したツールです

new=$( printf "%s" "$t" | tr -cs 'a-zA-Z0-9' '-' )
new=${new#-}; new=${new%-}

ありがとう、+ 1、思い出せませんtr...しかし、私はバッシュでそれをsedecho "$t" | sed -r 's/[^A-Za-z0-9]+/-/g'
成し遂げよ

競合するため、反対票を投じましたNote: I don't want to go with sed or other tools
Paul Calabro

3

純粋なbashを使い続けたい場合は、2パスソリューションで解決する必要があります。bash文字列の置換では、正規表現ではなく、パス名の展開のようにglobsを使用します。グロブで唯一の特殊文字は、、そして、そのラフ同等の正規表現であり、と。見てみましょうWooledge ウィキとのmanページのセクションおよび詳細はを。*?[].*.[] bash(1)Parameter ExpansionPathname Expansion

コメントと同じように、純粋なbashでの2パス展開は、外部プログラムを呼び出して同じことを行うよりも高速である可能性が高いため、あまり心配しません。


ありがとう、リンクをチェックします。私の心配は、スクリプト全体でこの作業を複数回実行する必要があることです。そのため、私の唯一の懸念は、同じコードを何度も繰り返して読みやすくすることです。とにかく投稿する丁寧な解決策を考えています。乾杯
ニューリノ

そのコードを関数に配置して、コードの繰り返しを避けることができます。
jw013 2011年

それは私がやっていることですが、ご存知のように、bash関数は文字列を返すことができません...または、少なくとも10分前に私が思っていたものでした:)
neurino

4
ここではいくつかやる-sの例と-ドント-sがある- バッシュはglob動作を拡張上記の例で...、それは次のようになりますshopt -s extglob; t="${t//+([^A-Za-z0-9])/-}"
Peter.O

1
@fered:ありがとう、非常に興味深い、私はそれをチェックする。リンクのURLに余分な文字が含まれ、404が返されます。動作しているのはBash Extended Globbingです
neurino
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.