web-dev-qa-db-ja.com

パスと拡張子なしでファイルbasenameをbashで抽出する

次のようなファイル名を付けます。

/the/path/foo.txt
bar.txt

私は得ることを願っています:

foo
bar

なぜこれがうまくいかないのですか?

#!/bin/bash

fullfile=$1
fname=$(basename $fullfile)
fbname=${fname%.*}
echo $fbname

それをする正しい方法は何ですか?

275
neversaint

外部のbasenameコマンドを呼び出す必要はありません。代わりに、以下のコマンドを使用することができます。

$ s=/the/path/foo.txt
$ echo ${s##*/}
foo.txt
$ s=${s##*/}
$ echo ${s%.txt}
foo
$ echo ${s%.*}
foo

この解決法は最近の( post 2004 _ posix _ に準拠したシェル(例:bashdashkshなど)でうまくいくはずです。

出典: シェルコマンド言語2.6.2パラメータの拡張

Bash文字列操作の詳細: http://tldp.org/LDP/LG/issue18/bash.html

557
ghostdog74

basename コマンドには2つの異なる呼び出しがあります。一方ではパスだけを指定します。その場合は最後のコンポーネントになります。もう一方では削除する接尾辞も付けます。そのため、2回目のbasenameの呼び出しを使用することでコード例を単純化できます。また、物事を正しく引用するように注意してください。

 fbname = $(ベース名 "$ 1" .txt)
 echo "$ fbname" 
256

Basenameとcutの組み合わせは、.tar.gzのようにダブルエンディングの場合でもうまく機能します。

fbname=$(basename "$fullfile" | cut -d. -f1)

この解がBash Parameter Expansionよりも少ない演算能力で済むなら、面白いでしょう。

51
kom lim

純粋なbash、no basename、no変数ジャグリング。文字列とechoを設定します。

s=/the/path/foo.txt
echo ${s//+(*\/|.*)}

出力:

foo

注:bash extglob オプションは "on"にする必要があります(on Ubuntuはデフォルトで "on"です)。

shopt -s extglob

${s//+(*\/|.*)}を歩く:

  1. ${s - $ sで始まります。
  2. //はパターンのすべてのインスタンスを置き換えます。
  3. +(は、括弧内のパターンリスト1つ以上に一致します。
  4. *\/は、/より前のものに一致します。 (第1パターン)
  5. |または。 (パターンセパレータ)
  6. .*は、.の後にあるものに一致します。 (第2パターン)
  7. ) end パターンリスト
  8. }終了パラメータの拡張 - /(これは文字列の代わりになるでしょう)がないので、マッチしたパターンは削除されます。

関連するman bash背景:

  1. パターン置換
  ${parameter/pattern/string}
          Pattern substitution.  The pattern is expanded to produce a pat‐
          tern just as in pathname expansion.  Parameter is  expanded  and
          the  longest match of pattern against its value is replaced with
          string.  If pattern begins with /, all matches  of  pattern  are
          replaced   with  string.   Normally  only  the  first  match  is
          replaced.  If pattern begins with #, it must match at the begin‐
          ning of the expanded value of parameter.  If pattern begins with
          %, it must match at the end of the expanded value of  parameter.
          If string is null, matches of pattern are deleted and the / fol‐
          lowing pattern may be omitted.  If parameter is @ or *, the sub‐
          stitution  operation  is applied to each positional parameter in
          turn, and the expansion is the resultant list.  If parameter  is
          an  array  variable  subscripted  with  @ or *, the substitution
          operation is applied to each member of the array  in  turn,  and
          the expansion is the resultant list.
  1. 拡張パターンマッチング
  If the extglob Shell option is enabled using the shopt builtin, several
   extended  pattern  matching operators are recognized.  In the following
   description, a pattern-list is a list of one or more patterns separated
   by a |.  Composite patterns may be formed using one or more of the fol‐
   lowing sub-patterns:

          ?(pattern-list)
                 Matches zero or one occurrence of the given patterns
          *(pattern-list)
                 Matches zero or more occurrences of the given patterns
          +(pattern-list)
                 Matches one or more occurrences of the given patterns
          @(pattern-list)
                 Matches one of the given patterns
          !(pattern-list)
                 Matches anything except one of the given patterns
14
agc

ここでは手綱があります:

  1. $(basename ${s%.*})
  2. $(basename ${s} .${s##*.})

Bongbangとw4etwetewtwetが尋ねたのと同じように、これが必要でした。

13
sancho.s

これは、ファイル名または拡張子を取得するもう1つの(より複雑な)方法です。最初にrevコマンドを使用してファイルパスを反転し、最初の.から切り取り、次にファイルパスを再度反転します。

filename=`rev <<< "$1" | cut -d"." -f2- | rev`
fileext=`rev <<< "$1" | cut -d"." -f1 | rev`
9
higuaro

もしあなたがWindowsのファイルパス(Cygwinの下で)を使ってNiceをプレイしたいのなら、これも試すことができます。

fname=${fullfile##*[/|\\]}

これは、Windows上でBaSHを使用しているときのバックスラッシュの区切り文字の説明になります。

2
Apelsin

このスレッドの投稿と、私がよく知っている小さな知識ベースを組み合わせて、拡張機能を抽出するための私の考えた代替案です。

ext="$(rev <<< "$(cut -f "1" -d "." <<< "$(rev <<< "file.docx")")")"

注意:私の引用符の使用について教えてください。それは私のために働いたが、私は彼らの適切な使用法で何かを見逃しているかもしれません(私はおそらく多すぎる)。

0
Diomoid