こんにちは。ヘッド、テール、パイプ(最終的にリダイレクト)のみを使用して、文字列の開始、中間、終了を抽出して出力する方法があるかどうか疑問に思います。
例: 次の文字列が与えられた場合、SHOWpijfirefjTHISezpijSTRING
コマンドは「SHOWTHISSTRING」を出力する必要があります。
私は次のことを試しました
(head -c 4 mdp > /dev/tty) | (tail -c +13 mdp | head -c 4 > /dev/tty) | (tail -c 6 mdp > /dev/tty) 2>&1
ただし、常に同じ結果を返すわけではなく、順序付けされていない結果を提供することもできます。
答え1
head
非標準-c
オプションをサポートし、固定バイト数を出力するように要求されたときに、入力が必要以上に読み取らないほどスマートな実装を使用できます。
string='SHOWpijfirefjTHISezpijSTRING'
printf %s "$string" | {
head -c 4
head -c 9 > /dev/null
head -c 4
tail -c 6
}
head
GNUのhead
組み込み関数では機能しますksh93
が、head
busyboxでは機能しない方法を確認してください。を実行すると、strace -fe read busybox sh ./that-script
次のようになります。
[pid 7739] read(0, "SHOWpijfirefjTHISezpijSTRING", 4096) = 28
1つ目はhead
ブロック全体を読み取ってすべての入力を消費し、そのうち4バイトを出力するため、次のコマンドとhead
コマンドについてtail
読み取ることができません。
GNUまたはksh93を使用している場合head
:
[pid 10293] read(0, "SHOW", 4) = 4
また、文字1head
の代わりにバイトtail
が使用されるため、-c
固定数の文字を報告するためにのみ使用でき、テキストは文字ごとに1バイトにエンコードされます。
ほとんどの最新のシェルには、文字位置に基づいて文字列を分割する演算子が組み込まれています。
たとえば、zsh または yash では次のようになります。
slice=${string[1,4]}${string[14,17]}${string[-4,-1]}
zshでは、次のように短縮できます。
slice=$string[1,4]$string[14,17]$string[-6,-1]
一部の部品を所定の位置から切り取ることができます。
$ string[5,13]= string[9,-7]=
$ print -r -- $string
SHOWTHISSTRING
または最新バージョンのksh93
、または以下bash
を使用してください。zsh
mksh
slice=${string:0:4}${string:13:4}${string: -6}
POSIX的に:
tmp=${string#?????????????}
slice=${string%"${string#????}"}${tmp%"${tmp#????}"}${string#"${string%????}"}
それにもかかわらず氏お勧めできます。このオプションは、一貫性を維持するためにいくつかの-c
実装に追加され、文字が複数のバイトで構成される可能性があるという概念が出てくるずっと前に追加されました。head
-c
tail
-c
tail
答え2
head
そしてtail
そのオプションをサポートすると仮定すると、-c
文字列はマルチバイト文字のない単純なASCIIにすぎず、シェルは<<<
ここで文字列構成をサポートします(bashとzshの両方をサポート)。次のことができます。
$ string=SHOWpijfirefjTHISezpijSTRING
$ printf '%s%s%s\n' "$(head -c 4 <<<"$string")" \
"$(head -c 17 <<<"$string" | tail -c 4)" \
"$( tail -c 5 <<<"$string")"
SHOWTHISRING
または望ましくない場合printf
:
$ string=SHOWpijfirefjTHISezpijSTRING
$ head -c 4 <<<"$string"; \
head -c 17 <<<"$string" | tail -c 4; \
tail -c 5 <<<"$string";
SHOWTHISRING