5

ループで処理される値をプッシュするには、シェルスクリプトでスタックを作成する必要があります。最初の要件は、スクリプトをポータブルインストーラーとして使用したいので(少なくともUnixライクなオペレーティングシステム間では)、これをポータブルな方法で実装する必要があるということです。2番目の要件は、ループがエントリを再帰的に処理しているときに新しい情報が表示される可能性があるため、ループ内で変更できる必要があることです。3番目の要件は、エントリごとに複数の情報行があることです(これはほとんど固定数であり、そうでない場合は、最初の情報行に基づいて計算できます)。

私の試みはスタックファイルを使用することです:

#!/bin/sh

echo "First entry" > stack.txt
echo "More info for the first entry" >> stack.txt
echo "Even more info for the first entry" >> stack.txt

while read ENTRY < stack.txt; do
    INFO2=`tail -n +2 stack.txt | head -n 1`
    INFO3=`tail -n +3 stack.txt | head -n 1`

    tail -n "+4" stack.txt > stack2.txt

    # Process the entry...

    # When we have to push something:
    echo "New entry" > stack.txt
    echo "Info 2" >> stack.txt
    echo "Info 3" >> stack.txt

    # Finally, rebuild stack
    cat stack2.txt >> stack.txt
done

これは、気分が悪いことを除いて、完全に機能します。これを行うための「ハッキー」な方法はありますか?

助けてくれてありがとう!

4

5 に答える 5

2

ここのセクション「例27-7。空の配列と空の要素」を確認してください。具体的には、コメントによると、上記は「プッシュ」であり、「ポップ」は次のとおりです。

http://tldp.org/LDP/abs/html/arrays.html

要素ごとに複数の行をエンコードする場合は、base64またはJSONで行をエンコードすることをお勧めします。urlエンコードを使用したり、echoを使用して文字をエスケープしたりすることもできます。

配列を使用する必要があるため、shでこの配列の例を使用できる場合があります。

http://www.linuxquestions.org/questions/linux-general-1/how-to-use-array-in-sh-shell-644142/

于 2012-10-04T02:13:23.593 に答える
2

ファイルを使用するよりも、ディレクトリを使用して各アイテムを独自のファイルに保存する方が簡単なようです。例えば:

#!/bin/sh 

count=0
push() { echo "$*" > $stackdir/item.$((++count)); }
pop() { 
    if test $count = 0; then
        : > $stackdir/data
    else
        mv $stackdir/item.$((count--)) $stackdir/data
    fi
}
trap 'rm -rf $stackdir' 0
stackdir=$( mktemp -d ${TMPDIR-/tmp}/stack.XXXX )

push some data
push 'another
data point, with
multiple lines'

pop
# Now $stackdir/data contains the popped data
cat $stackdir/data   # Print the most recently item pushed
push yet more data
pop
cat $stackdir/data   # Print 'yet more data'
pop
cat $stackdir/data
于 2012-10-05T01:37:18.017 に答える
0

残念ながら、猫を使った解決策はうまくいかないと思います。Linuxでも動作するかもしれませんが、私はFreeBSDを使用しており、catを使用して一時ファイルの内容をインポートしようとしましたが、常に失敗しました。

catの問題(少なくともFreeBSDの場合)は、シェルがその出力をリテラルコマンドとして解釈し、特定の文字をトリップすることで、これも問題を引き起こします。

私の最終的な解決策は、上記の一時ファイルを変数のホルダーに変換してから、sourceコマンドを使用してそれらをインポートすることでした。これは機能しますが、私はそれが好きではありません。主な理由は、データの前に変数名を付け、引用符で囲むために、saidで醜いカットを行う必要があるためです。

したがって、データファイルには次のようになります。-

variable=foobar

次に、スクリプトで、変数の出力を作成したものをすべて実行し、それをスクリプトに取り込むには、次を使用します。-

source datafile

その時点で、変数を使用できます。

それでも、これは実際にはスタックに似ていませんが、データを格納するために機能します。シェルスクリプトで単独の変数を使用することも、回避できるのであれば好きではありません。主な理由は、これも醜い代替ハッカーに頼ることを意味し、デバッグが面倒になる可能性があるためです。

于 2013-11-04T16:44:19.680 に答える
0

これはかなりクロスプラットフォームである必要があります。配列を使用しないため、古いバージョンのシェルで動作します。

Push(){ let Stack++;eval "Item$Stack=\"$1\"";}
Pop(){ eval "echo -e \$Item$Stack;unset Item$Stack";let Stack--;}
Append(){ Push "`Pop`\n$1";}

Push$Item1、、など$Item2の変数にデータを配置します。次の$Item3ように使用します。

Push data; Push 'more data'; Push "remember to escape \"quotes\""

Pop内容を出力した後、それ自体で最大番号の$Item変数を破棄します。内容を別の変数に格納するには、次のようにします。

Variable=`Pop`

Appendスタックの一番上にある変数に行を追加します。例えば:

Push "too much is always better than not enough"
Append "but it's almost as bad"

$Stackスタックの高さを格納します。これらの関数にはエラー処理がないため、スタックのアンダーフローがある場合はリセットする必要があります。さらに良いことに、1つを防ぐためにそれをチェックすることができます-1つ以上でPopないAppend限り、チェックしないでください。$Stack

于 2018-12-21T23:42:10.160 に答える
-1

バシズムは嫌ですよね?プログラムに配列が必要な場合は、...アセンブラ(冗談)を使用する必要があります。さて、これは私がPOSIXシェルでスタックを実装した方法です:

#!/bin/sh

# --------------------
# Stack implementation
# --------------------

s=""
stk=""
STACK_MAX_SIZE="65536"

# Delete all values from the stack:
stack_clear () {
    s=""
    stk=""
}

# To push a value into the stack:
stack_push () {
    local counter
    local cnt
    counter=$(echo -n "${s}" | wc --bytes)
    cnt=$(echo -n "${counter}" | wc --bytes)
    # ----- Internal check begin -----
    check=$(echo -n "${cnt}" | wc --bytes)
    if test "${check}" != "1"
    then
        echo "Internal error: it is real to meet such a long string..."
        exit 2s
    fi
    # ----- Internal check end -----
    stk=$(echo -n "${stk}${s}${counter}${cnt}")
    local check
    check=$(echo -n "${stk}" | wc --bytes)
    if test "${check}" -gt "${STACK_MAX_SIZE}"
    then
        echo "Error: stack overflow."
        exit 1
    fi
}

# To pull a value from the stack:
stack_pop () {
    local counter
    local cnt
    if test "${stk}" = ""
    then
        echo "Error: trying to pop from an empty stack."
        exit 1
    fi
    cnt=$(echo -n "${stk}" | tail --bytes=1)
    stk=$(echo -n "${stk}" | head --bytes=-1)
    counter=$(echo -n "${stk}" | tail --bytes=${cnt})
    stk=$(echo -n "${stk}" | head --bytes=-${cnt})
    s=$(echo -n "${stk}" | tail --bytes=${counter})
    stk=$(echo -n "${stk}" | head --bytes=-${counter})
    # ----- Internal check begin -----
    local check
    check=$(echo -n "${s}" | wc --bytes)
    if test "${check}" != "${counter}"
    then
        echo "Internal error: the stack is damaged."
        exit 2
    fi
    # ----- Internal check end -----
}

# ---------------
# The entry point
# ---------------

# Push "one", "two", "three" into the stack:
s="one"; stack_push
s="two"; stack_push
s="three"; stack_push

# Extract all the data from the stack:
while test "${stk}" != ""
do
    stack_pop
    echo "${s}"
done
于 2017-06-30T00:38:58.157 に答える