シェルスクリプトで文字列の最初の2文字を抽出する方法


123

たとえば、次の場合:

USCAGoleta9311734.5021-120.1287855805

抽出したいだけです:

US

6
みんな、ありがとう。結局、 'cut -c1-2'を使用してしまいましたが、正直なところ、 'cut'が存在することすら知りませんでした。私はコマンドラインでかなりの経験があると言いたいのですが、明らかに多くのことを学ぶ必要があります。
グレッグ

1
@Greg、カットは別のプロセスとして実行されることに注意してください-私の回答で一緒に投稿したinternal-bashソリューションよりも遅くなります。巨大なデータセットを処理している場合を除いて、それは何の違いもありませんが、それを覚えておく必要があります。
paxdiablo 2009

編集実際には、このコード行はおそらくレポートごとに約50,000回実行されると思います。だから私は内部のBashメソッドを使うかもしれません-あなたが言ったようにいくつかの多くの必要なリソースを節約します。
グレッグ

回答:


180

おそらく、bashシェルを使用している(そしてコメントに基づいて使用しているように見える)場合、最も効率的な方法は、パラメーター拡張のサブストリングバリアントを使用することです。

pax> long="USCAGol.blah.blah.blah"
pax> short="${long:0:2}" ; echo "${short}"
US

これはshortの最初の2文字に設定されますlonglongが2文字より短い場合は、shortそれと同じになります。

プロセスを作成するオーバーヘッドがないため、このインシェルメソッドは、多くの場合(レポートごとに50,000回など)行う場合に適しています。外部プログラムを使用するすべてのソリューションは、そのオーバーヘッドの影響を受けます。

最小の長さも確保したい場合は、事前に次のようなものを埋め込むことができます。

pax> long="A"
pax> tmpstr="${long}.."
pax> short="${tmpstr:0:2}" ; echo "${short}"
A.

これにより、長さが2文字未満の場合は、右側にピリオドが埋め込まれます(または、何かを作成するときに使用される文字を変更するだけでtmpstr)。これが必要かどうかは明らかではありませんが、完全を期すために入れておきます。


そうは言っても、外部プログラムを使用してこれを行う方法はいくつもあります(bash使用できない場合など)。そのいくつかは次のとおりです。

short=$(echo "${long}" | cut -c1-2)
short=$(echo "${long}" | head -c2)
short=$(echo "${long}" | awk '{print substr ($0, 0, 2)}'
short=$(echo "${long}" | sed 's/^\(..\).*/\1/')

最初の2つ(cutおよびhead)は、単一行の文字列と同じです。基本的には、どちらも最初の2文字を返すだけです。彼らはcutあなたに各行の最初の2文字を与えるという点で異なり、headの最初の2文字を提供し、入力全体の最初の2文字をます。

3番目は、awkサブストリング関数を使用して最初の2文字を抽出し、4番目はsedキャプチャグループ(()およびを使用\1)を使用して最初の2文字をキャプチャし、行全体をそれらに置き換えます。どちらも似ていますcut-入力の各行の最初の2文字を配信します。

入力が単一の行であることが確実である場合、それらはどれも重要ではありません。それらはすべて同じ効果をもたらします。


私はむしろ使用するprintf '%s'代わりのをecho:奇妙な文字が文字列である場合にはstackoverflow.com/a/40423558/895245 POSIXの場合は取り付か:head -cPOSIXではない、cut -cawk substr、あるsed \1かわかりません。
Ciro Santilli郝海东冠状病六四事件法轮功

1
@CiroSantilli新疆改造中心996ICU六四事件はprintfを使用しており、追加のプログラムは必要ありません。私の答えをください。
bschlueter

60

最も簡単な方法は

${string:position:length}

これ$length$stringat から部分文字列を抽出する場所$positionます。

これはbashの組み込みなので、awkやsedは必要ありません。


これは、部分文字列を取得する、短くて甘くて最も簡単な方法です。
ani627 2016

34

あなたは、いくつかの良い答えを得ていると私は自分自身組み込みバッシュで行くと思いますが、あなたはについて尋ね以来sedawkと(ほとんどそれらに基づいて)誰も他に提供するソリューションは、私はあなたにこれらを提供します:

echo "USCAGoleta9311734.5021-120.1287855805" | awk '{print substr($0,0,2)}'

そして

echo "USCAGoleta9311734.5021-120.1287855805" | sed 's/\(^..\).*/\1/'

awk一つはかなり明白であるべきだが、ここでの説明ですsed1:

  • 「s /」に置き換えます
  • 行「^」の先頭から始まり、任意の文字「。」が続く任意の文字「..」の2つのグループ「()」「*」を0回以上繰り返します(一部の特殊文字をエスケープするにはバックスラッシュが必要です)
  • 「/」によって、最初の(この場合のみ)グループの内容(ここで、バックスラッシュは、一致するサブ式を参照する特別なエスケープです)
  • 「/」完了

1
awkでは、文字列はインデックス1から始まるため、を使用する必要がありますsubstr($0,1,2)
アイザック

8

にいる場合はbash、次のように言うことができます。

bash-3.2$ var=abcd
bash-3.2$ echo ${var:0:2}
ab

これで十分かもしれません…


これが最も簡単で簡単な答えです。チャームのように働きました
アロハ

7

ただgrep:

echo 'abcdef' | grep -Po "^.."        # ab

私のニーズに合います。-Pオプションを削除して短くすることができます。すべての正規表現はそのパターンを理解します。
datashaman

6

使用できますprintf

$ original='USCAGoleta9311734.5021-120.1287855805'
$ printf '%-.2s' "$original"
US

5

—ファイルから列を削除する

最初の2文字を残すには、3から始まる列を削除するだけです

cat file | colrm 3


2

シェルスクリプトを使用し、POSIX以外の拡張機能(いわゆるbashismなど)に依存しない場合は、grep、sed、cut、awkなどの外部ツールをフォークする必要のない手法を使用できます。スクリプトの効率を下げます。おそらく、効率とposixの移植性はユースケースでは重要ではありません。しかし、それが(または良い習慣として)場合は、次のパラメーター拡張オプションメソッドを使用して、シェル変数の最初の2文字を抽出できます。

$ sh -c 'var=abcde; echo "${var%${var#??}}"'
ab

これは、「最小の接頭辞」パラメーター展開を使用して最初の2文字(これは部分)を削除し${var#??}、次に「最小の接尾辞」パラメーター展開${var%部分)を使用して、元の2文字以外のすべての文字列を削除します。値。

この方法は、「シェル=変数が#で始まるかどうかを確認する」という質問に対するこの回答ですでに説明されています。その回答は、ここでの元の質問に適用されるものとは少し異なるコンテキストで使用できる2つの類似したパラメーター拡張メソッドについても説明しています。


ベストアンサー、上にする必要があります。フォークもバシズムもありません。ダッシュなどの小さなシェルでも機能します。
exore

1

システムが(ではなくbash)別のシェルを使用しているが、システムにはがあるbash場合でも、変数bashを使用して呼び出すことにより、の固有の文字列操作を使用できbashます。

strEcho='echo ${str:0:2}' # '${str:2}' if you want to skip the first two characters and keep the rest
bash -c "str=\"$strFull\";$strEcho;"

これはメインの回答と同じ方法をbash使用します。まだ使用していない場合にのみ呼び出します。
palswim 2017年

残念ながら、これには別のプロセスを呼び出すことによるオーバーヘッドがすべて伴いますが、そのオーバーヘッドは単純さと親しみやすさほど重要ではありません。
palswim 2017年

1

面白くするために、いくつか追加します。複雑すぎて役に立たないのですが、言及されていませんでした。

head -c 2 <( echo 'USCAGoleta9311734.5021-120.1287855805')

echo 'USCAGoleta9311734.5021-120.1287855805' | dd bs=2 count=1 status=none

sed -e 's/^\(.\{2\}\).*/\1/;' <( echo 'USCAGoleta9311734.5021-120.1287855805')

cut -c 1-2 <( echo 'USCAGoleta9311734.5021-120.1287855805')

python -c "print(r'USCAGoleta9311734.5021-120.1287855805'[0:2])"

ruby -e 'puts "USCAGoleta9311734.5021-120.1287855805"[0..1]'


0

if mystring = USCAGoleta9311734.5021-120.1287855805

print substr(mystring,0,2)

米国を印刷します

ここで、0は開始位置、2はどのように多くの文字を読み取るかです。


ええと...それはGW-BASICではありませんか?ああ、待ってくださいawk。最初はわかりませんでした。
追って通知があるまで一時停止。

0

これはあなたの後に何ですか?

my $string = 'USCAGoleta9311734.5021-120.1287855805';

my $first_two_chars = substr $string, 0, 2;

ref:substr


1
彼/彼女はおそらくシェルからこれを呼び出すことであることを考えると、より良い形は次のようになりますperl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'
チャス。オーエンス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.