などの文字列ファイルのパスが与えられた場合、/foo/fizzbuzz.bar
bashを使用してfizzbuzz
文字列の一部だけを抽出するにはどうすればよいですか?
などの文字列ファイルのパスが与えられた場合、/foo/fizzbuzz.bar
bashを使用してfizzbuzz
文字列の一部だけを抽出するにはどうすればよいですか?
回答:
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)"
basenameを使用して、これを実現するために以下を使用しました。
for file in *; do
ext=${file##*.}
fname=`basename $file $ext`
# Do things with $fname
done;
これは、ファイル拡張子についての事前の知識を必要とせず、ファイル名にファイル名(拡張子の前)にドットが含まれている場合でも機能します。basename
ただし、プログラムは必要ですが、これはGNU coreutilsの一部であるため、ディストリビューションに付属しています。
fname=`basename $file .$ext`
純粋なbashの方法:
~$ x="/foo/bar/fizzbuzz.bar.quux.zoom";
~$ y=${x/\/*\//};
~$ echo ${y/.*/};
fizzbuzz
この機能は、man 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
mystring=$1
、問題に対処します見つける?
echo "basename: $(basename "$mystring")"
- 完了後に現在のディレクトリにあるファイルのリストで置き換えられmystring='/foo/*'
ない場合。*
basename
を使用するbasename
と、ファイルの拡張子が何であるかがわかっていると思いますか?
また、さまざまな正規表現の提案では、複数の「。」を含むファイル名には対応できないと思います。
以下はダブルドットに対応しているようです。ああ、それ自体が「/」を含むファイル名(キックのみ)
Pascalを言い換えると、「申し訳ありませんが、このスクリプトは長すぎます。短くする時間はありませんでした」
#!/usr/bin/perl
$fullname = $ARGV[0];
($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
print $basename . "\n";
この回答で使用されているPOSIX準拠の構文に加えて、
basename string [suffix]
のように
basename /foo/fizzbuzz.bar .bar
GNUbasename
は別の構文をサポートしています。
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'
あなたは出力を得るでしょう
フィズバズ
提案された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
${parameter%word}
および${parameter%%word}
後続部分の一致セクションで見つけることができる情報。