/foo/fizzbuzz.bar
のような文字列ファイルのパスが与えられた場合、その文字列のfizzbuzz
部分だけを抽出するのにbashをどのように使用すればよいでしょうか。
これはBashの#と%演算子を使って行う方法です。
$ x="/foo/fizzbuzz.bar"
$ y=${x%.bar}
$ echo ${y##*/}
fizzbuzz
${x%.bar}
は、ドットの後のすべてを削除するための${x%.*}
、または最初のドットの後のすべてを削除するための${x%%.*}
とすることもできます。
例:
$ x="/foo/fizzbuzz.bar.quux"
$ y=${x%.*}
$ echo $y
/foo/fizzbuzz.bar
$ y=${x%%.*}
$ echo $y
/foo/fizzbuzz
ドキュメントは Bashマニュアル にあります。 ${parameter%Word}
と${parameter%%Word}
の末尾部分の一致セクションを探します。
basenameコマンドを見てください。
NAME=$(basename /foo/fizzbuzz.bar .bar)
純粋なbash。2つの別々の操作で行われます。
パス文字列からパスを削除します。
path=/foo/bar/bim/baz/file.gif
file=${path##*/}
#$file is now 'file.gif'
パス文字列から拡張子を削除します。
base=${file%.*}
#${base} is now 'file'.
Basenameを使う私はこれを達成するために以下を使いました:
for file in *; do
ext=${file##*.}
fname=`basename $file $ext`
# Do things with $fname
done;
これはファイル拡張子の先験的な知識を必要とせず、ファイル名の中にドットがあるファイル名(拡張子の前)がある場合でも機能します。それはプログラムbasename
を必要としますが、これはGNU coreutilsの一部なので、どんなディストリビューションでも出荷されるべきです。
純粋なbashの方法:
~$ x="/foo/bar/fizzbuzz.bar.quux.zoom";
~$ y=${x/\/*\//};
~$ echo ${y/.*/};
fizzbuzz
この機能は "bash"の "Parameter Expansion"で説明されています。非bashの方法はたくさんあります:awk、Perl、sedなど。
編集:ファイル内のドットサフィックスで動作し、サフィックス(拡張子)を知る必要はありませんが、しません'は名前自体の中のドットで動作します。
Basenameおよびdirname関数は、あなたが求めているものです。
mystring=/foo/fizzbuzz.bar
echo basename: $(basename "${mystring}")
echo basename + remove .bar: $(basename "${mystring}" .bar)
echo dirname: $(dirname "${mystring}")
出力があります:
basename: fizzbuzz.bar
basename + remove .bar: fizzbuzz
dirname: /foo
basename string [suffix]
のように
basename /foo/fizzbuzz.bar .bar
GNU basename
は別の構文をサポートします:
basename -s .bar /foo/fizzbuzz.bar
同じ結果で。違いと利点は、-s
が複数の引数をサポートする-a
を含むことです:
$ basename -s .bar /foo/fizzbuzz.bar /baz/foobar.bar
fizzbuzz
foobar
これは、-z
オプションを使用してNULバイトで出力を分離することにより、ファイル名セーフにすることもできます。たとえば、空白、改行、グロブ文字を含むこれらのファイル(ls
で引用):
$ ls has*
'has'$'\n''newline.bar' 'has space.bar' 'has*.bar'
配列への読み込み:
$ readarray -d $'\0' arr < <(basename -zs .bar has*)
$ declare -p arr
declare -a arr=([0]=$'has\nnewline' [1]="has space" [2]="has*")
readarray -d
にはBash 4.4以降が必要です。古いバージョンでは、ループする必要があります。
while IFS= read -r -d '' fname; do arr+=("$fname"); done < <(basename -zs .bar has*)
他の投稿で提案されているようにbasenameを使用できない場合は、いつでもsedを使用できます。これは(醜い)例です。それは最大ではありませんが、必要な文字列を抽出し、入力を必要な文字列に置き換えることによって機能します。
echo '/foo/fizzbuzz.bar' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'
これはあなたに結果をもたらすでしょう
フィズバズ
basename
を使うことはあなたがファイル拡張子が何であるか知っていると仮定します、そうではありませんか?
そして私は、さまざまな正規表現の提案が複数の "。"を含むファイル名に対応していないと信じています。
以下はダブルドットに対応しているようです。おお、それ自身に "/"を含むファイル名(ちょうどキックのために)
Pascalを言い換えれば、「このスクリプトは非常に長いのですみません。短くする時間はありませんでした」
#!/usr/bin/Perl
$fullname = $ARGV[0];
($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
print $basename . "\n";
Perl -pe 's/\..*$//;s{^.*/}{}'
提案されているPerlの解決策に注意してください。最初のドットの後にあるものはすべて削除されます。
$ echo some.file.with.dots | Perl -pe 's/\..*$//;s{^.*/}{}'
some
あなたがPerlでそれをやりたいのなら、これはうまくいきます:
$ echo some.file.with.dots | Perl -pe 's/(.*)\..*$/$1/;s{^.*/}{}'
some.file.with
しかし、Bashを使っているのであれば、y=${x%.*}
(または、拡張子がわかっていればbasename "$x" .ext
)を使った解決法はもっと簡単です。
ベース名はそれを行い、パスを削除します。指定されている場合、およびファイルのサフィックスと一致する場合は、サフィックスも削除されますが、コマンドに付けるサフィックスを知る必要があります。そうでなければ、mvを使用して、新しい名前が他の方法であるべきものを見つけ出すことができます。
フルパスなしでファイル名を取得するために、最高評価の回答と2番目に高い評価の回答を組み合わせます。
$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz