someletters_12345_moreleters.ext
という形式のファイル名を考えて、私は5桁を抽出してそれらを変数に入れたいと思います。
その点を強調するために、私はx文字数のファイル名と、それから両側に1つのアンダースコアで囲まれた5桁の文字列、それからx文字数の別のセットを持っています。 5桁の数字をとり、それを変数に入れたいのです。
私はこれが達成されることができるさまざまな方法の数に非常に興味があります。
cut :を使う
echo 'someletters_12345_moreleters.ext' | cut -d'_' -f 2
より一般的な
INPUT='someletters_12345_moreleters.ext'
SUBSTRING=$(echo $INPUT| cut -d'_' -f 2)
echo $SUBSTRING
x が定数の場合、次のパラメータ展開は部分文字列抽出を実行します。
b=${a:12:5}
ここで、 12 はオフセット(ゼロベース)、 5 は長さです。
数字の周囲のアンダースコアが入力で唯一のものである場合は、2つのステップで(それぞれ)プレフィックスとサフィックスを削除できます。
tmp=${a#*_} # remove prefix ending in "_"
b=${tmp%_*} # remove suffix starting with "_"
他のアンダースコアがある場合は、もっとトリッキーですが、とにかく実現可能です。 1つの式で両方の展開を実行する方法を誰かが知っていれば、私も知りたいです。
提示された両方のソリューションは純粋なbashであり、プロセスの生成は含まれていないため非常に高速です。
そのようなシーケンスの最初のものを使用して、数字がファイル名のどこにでもあることができる一般的な解決策:
number=$(echo $filename | egrep -o '[[:digit:]]{5}' | head -n1)
変数の一部を正確に抽出するもう1つの解決策:
number=${filename:offset:length}
あなたのファイル名が常にstuff_digits_...
のフォーマットを持っているなら、あなたはawkを使うことができます:
number=$(echo $filename | awk -F _ '{ print $2 }')
数字以外のすべてを削除するさらに別の解決策として、
number=$(echo $filename | tr -cd '[[:digit:]]')
cut -c startIndx-stopIndx
を使ってみてください
より厳密な情報が必要な場合は、次のようにman bashで検索することもできます。
$ man bash [press return key]
/substring [press return key]
[press "n" key]
[press "n" key]
[press "n" key]
[press "n" key]
結果:
$ {parameter:offset} $ {parameter:offset:length} 部分文字列の展開。 offsetで指定された文字から開始して、 パラメータの最大文字数まで拡張します。 lengthを省略すると、offsetで指定された文字からパラメータstart - の部分文字列に展開されます。 lengthとoffsetは 算術式です(下記の算術評価を参照)。 offsetが0未満の数値に評価されると、その値はparameterの値の末尾からのオフセットとして 使用されます。 - で始まる算術 式は、前の:からの空白 で区切られ、Use Default Values展開と区別される必要があります。長さが ゼロ未満の数値に評価され、parameterが@ではなく、インデックス付き配列または連想 配列でもない場合、値の最後からのオフセット として解釈されます。文字数ではなくパラメータ数が大きくなり、展開 - は2つのオフセットの間の文字になります。 parameterが @の場合、結果はoffから始まる長さ位置パラメーター - setです。 parameterが@または *で添字を付けられた添字付き配列名の場合、結果は $ {parameter [offset]}で始まる配列の長さのメンバになります。指定された配列の最大インデックスより1大きい負のオフセットが を基準にして取られます。連想配列に部分 文字列展開を適用すると、未定義の結果が生成されます。負のオフセットは、コロンと混同しないように少なくとも1つのスペースでコロンから分離する必要があることに注意してください。 位置パラメータが使用されていない限り、部分文字列のインデックス付けはゼロから始まります。その場合、インデックス付け はデフォルトで1から始まります。 offsetが0で、位置 パラメータが使用されている場合は、リストの先頭に$ 0が付きます。
この純粋なbashソリューションが登場しなかったのは驚きです。
a="someletters_12345_moreleters.ext"
IFS="_"
set $a
echo $2
# prints 12345
IFSを以前の値、またはその後unset IFS
に再設定することをお勧めします。
Jor's answer(私にとってはうまくいきません)の答えを基にしてください。
substring=$(expr "$filename" : '.*_\([^_]*\)_.*')
要件に従う
私は、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)
構文を使うだけです。
サブプロセスがなくても、次のことが可能です。
shopt -s extglob
front=${input%%_+([a-zA-Z]).*}
digits=${front##+([a-zA-Z])_}
これの非常に小さい変形はksh93でも動作します。
次の概念に焦点を当てると、
「(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で最初の実行のみ(3245ではなく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の内部ですべての処理を行うよりも速くはありません。
これは、数字の最初のブロックに一致し、周囲のアンダースコアには依存しない、プレフィックスサフィックス解決法です(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
これが私のやり方です。
FN=someletters_12345_moreleters.ext
[[ $FN =~ _([[:digit:]]{5})_ ]] && NUM=${BASH_REMATCH[1]}
注:上記は正規表現であり、アンダースコアで囲まれた5桁の特定のシナリオに制限されています。異なるマッチングが必要な場合は、正規表現を変更してください。
私はsed
のregexグループを扱う能力が大好きです。
> var="someletters_12345_moreletters.ext"
> digits=$( echo $var | sed "s/.*_\([0-9]\+\).*/\1/p" -n )
> echo $digits
12345
もう少し一般的なオプションは not で、数字シーケンスの始まりを示すアンダースコア_
があると仮定します。したがって、たとえばシーケンスの前にあるすべての非数を取り除きます: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_ubstituteのためのものです[0-9]+
は1桁以上の数字に一致\1
は、正規表現出力のグループn.1にリンクします(この場合、グループ0が完全一致、グループ1が括弧内の一致です)。p
フラグは_p_rinting用ですsed
の正規表現処理を機能させるために、すべてのエスケープ\
があります。
与えられた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
私の答えはあなたがあなたの弦から何を欲しているかについてもっとコントロールするでしょう。文字列から12345
を抽出する方法についてのコードは、次のとおりです。
str="someletters_12345_moreleters.ext"
str=${str#*_}
str=${str%_more*}
echo $str
abc
のような文字や_
や-
のような特殊文字を含む何かを抽出したい場合、これはより効率的です。例:あなたの文字列がこのようなもので、someletters_
の後から_moreleters.ext
の前にあるものすべてが欲しいなら:
str="someletters_123-45-24a&13b-1_moreleters.ext"
私のコードでは、あなたが望むものを正確に述べることができます。説明:
#*
一致するキーを含む前の文字列を削除します。ここで私たちが言及したキーは_
%
です。それは一致するキーを含む次の文字列を削除します。ここで私たちが言及した鍵は '_more *'です
あなた自身でいくつかの実験をしてください、そしてあなたはこれが面白いと思うでしょう。
わかりました、ここに空のストリングとの純粋なパラメータ置換が行きます。警告は、 someletters および moreletters を文字としてのみ定義したことです。それらが英数字の場合、これはそのままでは機能しません。
filename=someletters_12345_moreletters.ext
substring=${filename//@(+([a-z])_|_+([a-z]).*)}
echo $substring
12345
phpのsubstr( 'abcdefg'、2-1、3)と同じです。
echo 'abcdefg'|tail -c +2|head -c 3
Bash組み込みの 'expr'コマンドもあります。
INPUT="someletters_12345_moreleters.ext"
SUBSTRING=`expr match "$INPUT" '.*_\([[:digit:]]*\)_.*' `
echo $SUBSTRING
少し遅れましたが、この問題に遭遇したところ、次のことがわかりました。
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
Bashソリューション:
IFS="_" read -r x digs x <<<'someletters_12345_moreleters.ext'
これはx
と呼ばれる変数を上書きします。 var x
はvar _
に変更することができます。
input='someletters_12345_moreleters.ext'
IFS="_" read -r _ digs _ <<<"$input"