ランダムベンチマーク

ランダムベンチマーク

シェルスクリプトを使用して文字列の2D構造を入力および出力する概念を探索していますが、文字列に改行文字が含まれていないという制限があります。スペースを含めることができます。

私が試したい方法は、エスケープされていないスペースを水平軸の区切り文字として使用し、新しい行を垂直軸の区切り文字として使用することです。

実験のために、次のガジェットを使用してパラメータを確認してください。

❯ cat argshow                     
#!/bin/bash                       
                                  
ITERATION=1                       
while (( "$#" )); do              
  echo '$'"${ITERATION}: ${1}"    
  shift                           
  (( ITERATION ++ ))              
done                              

例:

❯ argshow abc\ def zzz
$1: abc def           
$2: zzz               

私が設定したルールに基づいた最初のテストケースは次のとおりです。

echo 'abc\ def ghi\njkl'

値を示します(JSON形式)。

[["abc def", "ghi"], ["jkl"]]

いいですね。

私はこれを最初に試しました。私はこれをzshシェルで実行しました。

❯ echo 'abc\ def ghi\njkl' | while read -r line; do argshow $line; done 
$1: abc\ def ghi                                                        
$1: jkl                                                                 

argshow最初の行で引数が2つあるはずですが、引数を1つ受け取ったので、これは気に入らません。-rforを使用してバックスラッシュを回復できることは良いことですread(タブについては後で心配します...)。

Bashシェルで同じコマンドを実行しました。

$ echo 'abc\ def ghi\njkl' | while read -r line; do argshow $line; done
$1: abc\
$2: def
$3: ghi\njkl
$ echo $'abc\ def ghi\njkl' | while read -r line; do argshow $line; done
$1: abc\
$2: def
$3: ghi
$1: jkl

これが私のbashの知識が限界に達するところです。これらのどれも私が期待したものではありませんでした。eval私が望む方法で動作するには、なぜ1つを接続する必要がありますか? :

$ echo $'abc\ def ghi\njkl' | while read -r line; do eval argshow $line; done
$1: abc def
$2: ghi
$1: jkl

bash変数を配置するときに引用符を使用しないと、変数が拡張され、必要なものに分割されるという印象を受けました。結局のところ、shellcheckシェルスクリプトでシェル変数を二重引用符で囲むことなく使用すると、それが私に叫ぶことです。常に拡張されると思ったので、変数に空白文字が2つあると、予想される引数1つではなく引数3つになります。

定期的に使用するスクリプトを作成するためにこの方法を使用することはできません。evalスクリプトを開始するには、多くの邪悪な穴があります。これは引数を引用符で囲むような無料の機能を可能にし、改行文字をエスケープすることができるので誘惑的である可能性があり、構文は慣れているので覚えやすいですが、スクリプトで使用するには危険すぎる可能性があります。コードの実行を引き起こすためにエスケープされていないセミコロンを挿入します。

おそらく私は実際に実際のプログラミング言語で実装する必要があると思われるシェルスクリプトの限界を見つけました。公平ですが、この問題を解決し、ハッキングを続行するために使用できるいくつかの簡単なオプションがあれば幸いです。

はい、また、bash配列の渡しなどの操作を実行できることもわかっていますが、これらのデータストリームを単純なファイルにダンプできるようにしたいです。それが最大の魅力です。暗黙的に非常に基本的な Function human- 読みやすい形式。


当面の仕事の背景知識をもう少し学びましょう。私は、コンピュータを活用するデータ管理方法をもう少し活用する方法に切り替えています。私の考えでは、カメラ/ドローンなどに512GB SDカードのようなものを使う場合があります。利便性とワークフローのために、いくつかの古いデータをメモリカードに保存したいと思います。たとえば、時々見やすくするために、Macbookに何かをダンプしたいと思います。これを私のワークステーションのZFSプールに移行するときにどのファイルが保存されているのか疑問に思うので、そのファイルをコピーしてスペースを無駄にする必要はありません。時にはこの側面に集中しすぎると、バックアップする必要がある新しいコンテンツを受け入れられないことがあります。再利用できるようにディスクを消去する前に、ディスクの残りの部分(ほとんどいっぱいになる可能性がある)を確認することは、常に時間のかかるプロセスです。

だから私が今使っているアプローチは、定期的にストレージプールデータベースを構築し、find /pool /pool2 -type f -printf "%M %s %t %p\\n" > ~/Dropbox/find_zfsさまざまな用途に簡単に使用できるようにすることです。この問題が発生した理由は、次のスクリプト(名前trawl)の作成中に発生しました。

#!/bin/bash

# provide a list of dirs and for each of their immediate child file and folder names, trawl through 
# a standard file listing record (this is the FIRST arg) (the kind I ususally use with fzf) to 
# look for any matches. emit human readable output on stderr, and stdout will be a list paths.

# That output will be organized for now as a flat list. The idea here is that the list-of-lists 
# structure of it can trivially be recovered by a wrapping script that knows the input args and can 
# correlate them back out. Inefficient, but simple.

# TODO TODO TODO implement a sanitizer on the input and do a fuzzy check for that to further 
# eliminate manual checking via fzf and suggest matches when they are found

FIRSTARG="$1"
shift

for DIR in "$@"; do
    >&2 echo "CHECKING DIR: $DIR"
    ls -1 "$DIR" | while read -r CHILD; do
        RG_OUT=$(rg -F "$CHILD" "$FIRSTARG")
        if [ $? -eq 0 ]; then
            >&2 echo "$DIR/$CHILD is found with $(echo "$RG_OUT" | wc -l) hits; skipping!"
        else
            >&2 printf "NOT FOUND; adding: "
            echo "$DIR/$CHILD"
        fi
    done
done

また、指定されたディレクトリの最初のレベルのサブファイルではなく、各ファイルをより徹底的に調べるために再帰バージョンを作成しました。

ご覧のとおり、このアイデアは基本的に半自動ファイルバックアップの重複排除を達成できることです。

もちろん、誰が言及する前に、おそらくZFS自体の重複排除を有効にするでしょう。しかし、一般的な合意は、(主に)バルクメディアバックアップなどの非常に狭いユースケースで課されるさまざまなパフォーマンスコストと同じくらい価値があるということです。それらの一つ。

これがどのように当てはまるかと尋ねることもできます。trawlここでは「同期点」が欲しかった。 2D 構造の 2 つの軸は、(X) 入力ディレクトリのすべての個々のサブファイルと (Y) です。 )個別にディレクトリを入力します。

私のスクリプトコメントに示すように、最終的に2D要件を回避するようになりました。それはそれがそれほど重要ではないことが判明し、後でこれを元に戻すことができたからです。実際に保存したい場合は、JSONをエクスポートするのが最も合理的です。

これにより、ワークフローは今

  • ディスクの挿入(該当する場合)
  • trawl ~/Dropbox/find_zfs srcdir/ srcdir2/
  • 出力を視覚的にチェックして意味があるかどうかを確認します。
  • 再実行しますが、入力をパイプします。mkdir -p /pool/backup-$(date +%F); while read -r LINE; do mv "$LINE" /pool/backup-$(date +%F); done

同じことをするために書いた実際のTypeScriptプログラムがあり、機能も同じですが、インタラクティブで柔軟なワークフローを実装するのは自然ではないので、ちょっと面白いです。

ベストアンサー1

1つの変数に複数の単語を含めるにはスカラー変数ではなく配列を使用し、それをエスケープ演算子(フィールド区切り文字と行の連続の場合)としてread扱う場合は省略します。これがデフォルトです。次のタスクは次のタスクではありません。実行。\-rread

したがって、ksh/zsh/yashから:

read -A fields; showargs "${fields[@]}"

またはbashで:

read -a fields; showargs "${fields[@]}"

(デフォルトでは、スペース、タブ、および改行(zshではnul)を含む文字read分割に注意してください。)$IFS

$IFSzshでは、他のBourne様シェルと同様に(ニーモニック:はさみのように見えます)を使用して、引用符なしのスカラー$=line変数$line拡張文字分割を実行できます。$=または、$=~line他のシェルによって実行される完全な分割+globの場合、shellcheckは警告します。または、現在含まれている${(s[ ])line}以上にスペースを明示的に分割します。$IFSしかし、ここではバックスラッシュには役に立ちません。

バックスラッシュ(シェル構文トークン化と引用符の削除用)だけでなく、任意のシェル構文引用符を処理するにeval@thrigの素晴らしい答えzshzおよびQパラメーター拡張フラグ情報。ただし、空の要素を維持するには、次の操作を行う必要があります。

$ line='foo\ bar "" blah'
$ fields=( "${(Q@)${(z)line}}" )
$ typeset fields
fields=( 'foo bar' '' blah )

あるいは、Z[n]代替z改行文字もコマンド区切り記号トークンの代わりにトークン区切り文字として扱われます。

それにもかかわらず、これは単に引用符ではなくフルシェル構文(この場合はzsh構文)トークン化を実行することです。たとえば、行は予期したものとは異なりa$(b c)<y>y<<<"a b"ます。fields=( 'a$(b c)' '<' y '>' y '<<<' 'a b' )fields=( 'a$(b' 'c)<y>y<<<a b' )

多次元配列とデータ(逆)シリアル化1をサポートするシェルについては、ksh93を参照してください。

$ printf '%s\n' $'( (\'a b\' a) (\'b\\c\n\' d) )' | 
> ksh -c 'read -C a; typeset -p a; printf "<%s>\n" "${a[1][0]}"'
typeset -a a=(('a b' a) ($'b\\c\n' d) )
<b\c
>

私が最後にテストしたとき(数年前)、バグがたくさんあり、おそらくそれでもそうです。eval入力が有効な直列化ストリームであるという保証がない場合。

ああ!そうではありません:

$ printf '%s\n' '( [`uname>&2`]=1 )' | ksh -c 'read -C a'
Linux

さらに、JSON文字列にはNULを含めることができますが、zsh変数にのみNULを含めることができます。複雑なデータ構造を処理するには、シェルの代わりに適切なプログラミング言語を使用する方が合理的です。


1記録によると、AT&Tは開発チームが解体される前にksh93の最後のベータ版をリリースしました。 ksh2020(現在は使用されていません)の基盤となるksh93も、JSON(逆)シリアル化のいくつかの実験的サポートを提供しました。 ksh2020から削除されました)。また、CSV入力/出力もサポートしています。

おすすめ記事