902

形式のファイル名を指定するsomeletters_12345_moreleters.extと、5桁を抽出して変数に入れたいと思います。

要点を強調するために、x 個の文字のファイル名と、両側に 1 つのアンダースコアで囲まれた 5 桁のシーケンス、さらに x 個の文字の別のセットがあります。5桁の数字を変数に入れたいです。

これを実現するさまざまな方法に非常に興味があります。

4

24 に答える 24

1324

これを行うには、パラメーター拡張を使用できます。

aが定数の場合、次のパラメーター展開によって部分文字列の抽出が実行されます。

b=${a:12:5}

ここで、12はオフセット (ゼロベース) で、5は長さです

数字の周りのアンダースコアが入力内の唯一のものである場合、次の 2 つの手順で接頭辞と接尾辞を (それぞれ) 取り除くことができます。

tmp=${a#*_}   # remove prefix ending in "_"
b=${tmp%_*}   # remove suffix starting with "_"

他のアンダースコアがある場合は、よりトリッキーではありますが、とにかく実行可能です。単一の式で両方の展開を実行する方法を誰かが知っている場合は、私も知りたいです。

提示された両方のソリューションは純粋な bash であり、プロセスの生成が含まれていないため、非常に高速です。

于 2009-01-09T15:52:35.563 に答える
854

使用カット:

echo 'someletters_12345_moreleters.ext' | cut -d'_' -f 2

より一般的な:

INPUT='someletters_12345_moreleters.ext'
SUBSTRING=$(echo $INPUT| cut -d'_' -f 2)
echo $SUBSTRING
于 2009-01-09T13:56:14.113 に答える
111

そのようなシーケンスの最初を使用して、番号がファイル名のどこにでもある一般的なソリューション:

number=$(echo $filename | egrep -o '[[:digit:]]{5}' | head -n1)

変数の一部を正確に抽出する別の解決策:

number=${filename:offset:length}

ファイル名が常にstuff_digits_...awk を使用できる形式の場合:

number=$(echo $filename | awk -F _ '{ print $2 }')

数字以外のすべてを削除するさらに別のソリューションを使用します

number=$(echo $filename | tr -cd '[[:digit:]]')
于 2009-01-09T14:00:08.723 に答える
109

使ってみるだけcut -c startIndx-stopIndx

于 2010-09-22T17:54:15.797 に答える
44

これが私がそれを行う方法です:

FN=someletters_12345_moreleters.ext
[[ ${FN} =~ _([[:digit:]]{5})_ ]] && NUM=${BASH_REMATCH[1]}

説明:

Bash 固有:

正規表現 (RE):_([[:digit:]]{5})_

  • _一致する文字列の一致する境界を画定/アンカーするリテラルです
  • ()キャプチャ グループを作成する
  • [[:digit:]]文字クラスです。それ自体が物語っていると思います
  • {5}前の文字、クラス (この例のように)、またはグループの正確に 5 つが一致する必要があることを意味します

英語では、次のように動作すると考えることができます。FN文字列は、キャプチャ グループが開か_れる時点で 5 桁の一致を試みるまで、1 文字ずつ繰り返されます。この時点までの照合が成功した場合、キャプチャ グループは通過した 5 桁を保存します。次の文字が の場合、条件は成功であり、キャプチャ グループが で使用可能になり、次のステートメントを実行できます。照合のいずれかの部分が失敗した場合、保存された詳細は破棄され、文字ごとの処理が. たとえば、whereの場合、一致が見つかるまでに 4 回の不正開始が発生します。_BASH_REMATCHNUM=_FN_1 _12 _123 _1234 _12345_

于 2009-01-12T19:43:20.790 に答える
37

より厳密な情報が必要な場合は、次のように man bash で検索することもできます

$ man bash [press return key]
/substring  [press return key]
[press "n" key]
[press "n" key]
[press "n" key]
[press "n" key]

結果:

${パラメータ:オフセット}
       ${パラメータ:オフセット:長さ}
              サブストリング展開。の長さの文字まで展開します
              オフセットで指定された文字から始まるパラメーター。もしも
              length は省略され、パラメータ start- の部分文字列に展開されます
              オフセットで指定された文字で ing。長さとオフセットは
              算術式 (以下の算術評価を参照)。もしも
              オフセットがゼロ未満の数値に評価される場合、その値が使用されます
              パラメータの値の末尾からのオフセットとして。算術
              - で始まる式は空白で区切る必要があります
              from the previous : Use Default と区別する
              価値観の拡大。長さが以下の数値に評価される場合
              ゼロであり、パラメーターが @ ではなく、インデックス付きでも連想型でもない
              配列、値の末尾からのオフセットとして解釈されます
              文字数ではなくパラメータの
              sion は、2 つのオフセットの間の文字です。パラメータが
              @、結果は of​​f で始まる位置パラメータの長さです。
              設定。parameter が @ またはで添字付けされたインデックス付き配列名の場合
              *、結果は、で始まる配列の長さのメンバーです
              ${パラメータ[オフセット]}。に対して負のオフセットが取られます。
              指定された配列の最大インデックスより 1 大きい。サブ-
              連想配列に文字列展開を適用すると unde‐
              罰金の結果。負のオフセットを分離する必要があることに注意してください
              混乱を避けるために、コロンから少なくとも1つのスペースで
              :- 展開で。部分文字列のインデックス作成はゼロから始まります。
              位置パラメータが使用されます。この場合、インデックス
              デフォルトでは 1 から始まります。オフセットが 0 の場合、位置
              パラメータが使用されている場合、$0 がリストの前に付けられます。
于 2013-05-31T15:00:54.763 に答える
21

jorの答えに基づいて構築します(これは私にはうまくいきません):

substring=$(expr "$filename" : '.*_\([^_]*\)_.*')
于 2009-01-09T15:41:11.937 に答える
13


「(1つまたは複数の)数字の連続」 という概念に焦点を当てると、

数値を抽出するために、いくつかの外部ツールを使用できます。
sed または tr のいずれかの他のすべての文字を非常に簡単に消去できます。

name='someletters_12345_moreleters.ext'

echo $name | sed 's/[^0-9]*//g'    # 12345
echo $name | tr -c -d 0-9          # 12345

しかし、 $name に複数の数字が含まれている場合、上記は失敗します:

「name=someletters_12345_moreleters_323_end.ext」の場合:

echo $name | sed 's/[^0-9]*//g'    # 12345323
echo $name | tr -c -d 0-9          # 12345323

正規表現 (regex) を使用する必要があります。
sed と perl で最初の実行 (323 ではなく 12345) のみを選択するには:

echo $name | sed 's/[^0-9]*\([0-9]\{1,\}\).*$/\1/'
perl -e 'my $name='$name';my ($num)=$name=~/(\d+)/;print "$num\n";'

しかし、bash (1)で直接行うこともできます。

regex=[^0-9]*([0-9]{1,}).*$; \
[[ $name =~ $regex ]] && echo ${BASH_REMATCH[1]}


これにより、他のテキスト/文字に囲まれた任意の 長さの数字の最初のランを抽出できます。

:regex=[^0-9]*([0-9]{5,5}).*$;正確に 5 桁のランのみが一致します。:-)

(1) : 短いテキストごとに外部ツールを呼び出すよりも高速です。大きなファイルの sed または awk 内ですべての処理を行うよりも高速ではありません。

于 2014-08-05T08:11:19.947 に答える
12

要件に従う

私は、x文字数のファイル名と、両側に1つのアンダースコアで囲まれた5桁のシーケンス、次にx文字数の別のセットを持っています。5桁の数字を変数に入れたいです。

grep役に立つかもしれないいくつかの方法を見つけました:

$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]+" 
12345

またはそれ以上

$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]{5}" 
12345

そして、-Po構文で:

$ echo "someletters_12345_moreleters.ext" | grep -Po '(?<=_)\d+' 
12345

または、正確に 5 文字に合わせたい場合は、次のようにします。

$ echo "someletters_12345_moreleters.ext" | grep -Po '(?<=_)\d{5}' 
12345

最後に、変数に格納するには、var=$(command)構文を使用するだけです。

于 2013-06-26T12:13:49.147 に答える
11

サブプロセスがなくても、次のことができます。

shopt -s extglob
front=${input%%_+([a-zA-Z]).*}
digits=${front##+([a-zA-Z])_}

これの非常に小さなバリアントもksh93で機能します。

于 2009-01-09T16:13:38.500 に答える
9

私の答えは、文字列から何を求めているかをより細かく制御できます。12345文字列から抽出する方法のコードは次のとおりです

str="someletters_12345_moreleters.ext"
str=${str#*_}
str=${str%_more*}
echo $str

や のような文字やabc特殊文字を含むものを抽出したい場合、これはより効率的です。例: 文字列がこのようなもので、 afterと before のすべてが必要な場合:_-someletters__moreleters.ext

str="someletters_123-45-24a&13b-1_moreleters.ext"

私のコードを使用すると、正確に何が欲しいかを言及できます。説明:

#*一致するキーを含む前の文字列を削除します。ここで言及したキーは_ %、一致するキーを含む次の文字列を削除します。ここで言及したキーは「_more*」です

自分でいくつかの実験を行ってください。これは興味深いものです。

于 2016-07-29T07:41:26.123 に答える
9

数字の最初のブロックに一致し、周囲のアンダースコアに依存しない接頭辞と接尾辞のソリューション (JB と Darron によって提供されたソリューションに類似) は次のとおりです。

str='someletters_12345_morele34ters.ext'
s1="${str#"${str%%[[:digit:]]*}"}"   # strip off non-digit prefix from str
s2="${s1%%[^[:digit:]]*}"            # strip off non-digit suffix from s1
echo "$s2"                           # 12345
于 2011-05-06T12:50:13.293 に答える
7

sed正規表現グループを処理する の機能が気に入っています。

> var="someletters_12345_moreletters.ext"
> digits=$( echo "$var" | sed "s/.*_\([0-9]\+\).*/\1/p" -n )
> echo $digits
12345

もう少し一般的なオプションは、数字シーケンスの開始を示すアンダースコアがあると仮定しない_ことです。したがって、たとえば、シーケンスの前に取得したすべての非数字を取り除きますs/[^0-9]\+\([0-9]\+\).*/\1/p


> man sed | grep s/regexp/replacement -A 2
s/regexp/replacement/
    Attempt to match regexp against the pattern space.  If successful, replace that portion matched with replacement.  The replacement may contain the special  character  &  to
    refer to that portion of the pattern space which matched, and the special escapes \1 through \9 to refer to the corresponding matching sub-expressions in the regexp.

正規表現に自信がない場合のために、これについて詳しく説明します。

  • s_s_substitute用です
  • [0-9]+1桁以上に一致
  • \1正規表現出力のグループ n.1 へのリンク (この場合、グループ 0 は一致全体、グループ 1 は括弧内の一致です)
  • pflag は _p_rinting 用です

すべてのエスケープは、の正規表現処理を機能\させるためにあります。sed

于 2016-10-21T08:12:04.813 に答える
6

test.txt が「ABCDEFGHIJKLMNOPQRSTUVWXYZ」を含むファイルであるとします。

cut -b19-20 test.txt > test1.txt # This will extract chars 19 & 20 "ST" 
while read -r; do;
> x=$REPLY
> done < test1.txt
echo $x
ST
于 2016-08-14T19:44:45.643 に答える
4

PHP の substr('abcdefg', 2-1, 3) に似ています。

echo 'abcdefg'|tail -c +2|head -c 3
于 2013-06-26T11:34:08.277 に答える
1

bash 組み込みの 'expr' コマンドもあります。

INPUT="someletters_12345_moreleters.ext"  
SUBSTRING=`expr match "$INPUT" '.*_\([[:digit:]]*\)_.*' `  
echo $SUBSTRING
于 2009-01-09T15:01:02.517 に答える
1

bash ソリューション:

IFS="_" read -r x digs x <<<'someletters_12345_moreleters.ext'

これにより、 という変数が上書きされxます。varは varxに変更できます_

input='someletters_12345_moreleters.ext'
IFS="_" read -r _ digs _ <<<"$input"
于 2016-01-22T05:45:24.207 に答える
1

これは、目的の出力を得るのに役立つかもしれません

コード :

your_number=$(echo "someletters_12345_moreleters.ext" | grep -E -o '[0-9]{5}')
echo $your_number

出力:

12345
于 2021-10-10T16:04:32.830 に答える
0

少し遅れましたが、この問題に遭遇したところ、次のことがわかりました。

host:/tmp$ asd=someletters_12345_moreleters.ext 
host:/tmp$ echo `expr $asd : '.*_\(.*\)_'`
12345
host:/tmp$ 

日付に %N がない組み込みシステムでミリ秒の解像度を取得するために使用しました。

set `grep "now at" /proc/timer_list`
nano=$3
fraction=`expr $nano : '.*\(...\)......'`
$debug nano is $nano, fraction is $fraction
于 2013-08-01T08:12:33.863 に答える