25k文字列を部分的に進める最良の方法は何ですか?

25k文字列を部分的に進める最良の方法は何ですか?

25,000文字があります。

printf私は任意の数の文字を順番に印刷するスクリプトを作成したいと思います。

説明する:

注文番号

どこ数字1〜25000の値にすることができ、この出力を得ることができます。

私はデータを別のファイルに保存したくない(最も簡単な解決策ですか?)POSIXシェルコマンドを使用することを好みます(スクリプトを可能な限り移植可能にするには:awkまたはPerlがこれを簡単にハックできることを知っています)あります)。 。

このデータを変数に保存する必要がありますか?または、コマンド()を介してprintfプログラム全体を実行しますか?それとも別の(より良い?)解決策がありますか?なぜ他のオプションよりも1つのオプションを選択するのですか?cutcut -c -$1

私が見落とした他の問題/警告は何ですか?

答え1

このdd順序を考えてみましたか?これにより、必要な数のバイトをスキップし、必要な数のバイトを出力できます。

dd if=infilename bs=1 skip=sk count=ct 2>/dev/null

dd、ファイル名を入力、ブロックサイズ1、最初にスキップSKファイルのバイトを入力してコピーします。CTバイトを標準出力に送信します(または指定されたファイルを使用します of=name)。通常、最後に印刷されるステータスメッセージを防ぐには、エラーメッセージをリダイレクトしてください。

答え2

移植性と信頼性を考慮して、ビッグデータを変数として保存することは良い考えではないかもしれません。awk移植しやすい非POSIXソリューションの場合sed

説明する

データ量が多い場合は変数として保存しないでください。しかし、Bash自体に制限はありませんが、オペレーティングシステムに制限がある可能性があります。

「私のオペレーティングシステムで動作します」としましょう。しかし、

  • オペレーティングシステムごとに制限が異なります。
  • したがって、移植性を最大限にしたい場合は、なぜスクリプトがあるオペレーティングシステムで実行され、別のオペレーティングシステムでクラッシュする危険性がありますか?
  • したがって、最初に変数に保存しないことでこの問題を回避してください。

次にファイルに保存します。特に、文字列を文字(または必要な最小単位)とは別の行に分割します。

次に、次を使用しますsed

  • sedは大容量ファイル全体をロードする必要はなく、1行ずつ機能します。
  • sedPOSIX仕様で定義、あなたの要件を満たしていますnon-AWKが、まだPOSIXです。

また、ファイル使用のコード保守の利点も考慮してください。スクリプトでコードをナビゲートするよりも、ファイルに保存されている行を更新する方が簡単です。

はい

ファイルには、1行に1文字(または「段階的」にしたい最小単位)のデータが含まれていますdata.lst

a
b
c
d
e

以下を含めることができますscript.sh

#!/bin/bash

stop_number="$1"

sed -n "1,${stop_number}p" data.lst

したがって、コマンドプロンプトでテストして次のことを確認してください。

$ ./script.sh 3
a
b
c
  • で指定した数だけ行をsed印刷するために使用されます。明確にするために直接書くのではなく1$stop_number$stop_number$1
  • $stop_numberもちろん、$1入力したい任意の数値である位置パラメータを介して取得します。
  • data.lstしたがって、表示される順序で3つの文字に正常に従います。data.lst
  • このとき、実際の行数より大きい数字を入力すると、すべての行のみが表示されます。
  • 現在はdata.lst同じディレクトリにありますが、script.sh望ましくない場合、実際に別の場所にある場合は、~/some/dir/data.lst次のように調整します。~/some/dir/data.lst

したがって、実際のデータがある場合は、data.lstこのスクリプトを直接テストできます。

答え3

Tomから少し借りるには:

#!/bin/sh
skp(){  dd bs="$1" skip=1 count=0; }    # direct seek to target
rd (){  dd bs="$1" skip=0 count=1; }    # single read at target
tail=$(sed -ne'/^don/{=;q;}' <"$0")     # skip script by line#
while   [ 1 -gt "$#" ] && exit          # exit when args exhausted
        exec <&- <"$0" || exit          # exec <"$0" each iteration
do      head -n "$tail" >&3             # only consider the tail
        case ${2+$1}  in                # test args
        (*[1-9]*|-*[!0]*)               # skp() when ${2++} && $1 != 0
          skp "$1";esac 2>&3            # send stderr to dev/null
          rd  "${2-$1}" 2>&3            # else just rd() from head of offset
        echo; shift ${2+"2"}            # append a newline and shift args away
done    3>/dev/null                     # put your data below this

変数に入れないでファイルに入れてください。 25k変数はシェルが処理するのは楽しくありません。追求シングルでは、ほぼ原子的行動。したがって、バイト23843 - 24843を印刷するには、上記の操作を実行した後、次のように呼び出すことができます。

myscript 23843 1000

...最初にaは、headファイル記述子の共有標準からスクリプト内のすべての行を削除し、オフセットが文字列の頭部の正確に25kに設定されるようにします。それから最初の行dd探すオフセットは〜23kで、2番目のオフセットはddそれを読み取ります。これが最も簡単な方法です。シェルは文字ごとに読み取るように設計されています。readたとえば、一般的なシェルの組み込み機能は次のことを行います。1バイト read()改行文字が見つかるまで繰り返し、改行文字が見つかるまで停止しないでください。各パラメータペアに対して1つの操作がdd実行されます。read

これが私がテストした方法です:

# after a copy to my clipboard
ddscr(){ sh /tmp/ddscr.sh "$@"; }
{ xsel; man man; } > /tmp/ddscr.sh
{ echo show the size; ls -l /tmp/ddscr*
  echo read from the top; ddscr 80
  echo from the middle;   ddscr 15k 160
  echo from the tail;     ddscr 64k | tail -n5
}

show the size
-rw-r--r-- 1 mikeserv mikeserv 37564 Dec 13 11:27 /tmp/ddscr.sh
read from the top
MAN(1)                           Manual pager utils                          MAN
from the middle
lso use manconv(1) directly.
              However, this option allows you to convert several manual pages to  a
              single  encoding  without  having
from the tail
       31st  March  2001  -  present day: Colin Watson <[email protected]> is now
       developing and maintaining man-db.

2.7.5                                2015-11-06                              MAN(1)

...そして...

ddscr 10k 10 20k 10 10250 10

       fi
is  option
le.   If

答え4

プログラムとデータを同じファイルにラップしたい場合は、最良の方法はperl。 ); Windowsでは標準では見つかりませんが、Windowsでも見つかりませんbash

#!/usr/bin/env perl
print substr(<DATA>, $ARGV[0], $ARGV[1]), "\n";

__DATA__
Just add all your text after 
the __DATA__ line... no fuss, no quoting, 
no tricks

たとえば、名前をselected_printとして指定し、10から始めて30文字を印刷するとします。

% selective_print 10 30

関連情報