3

追加(>>)の代わりに追加を処理する演算子(例:^>)を追加したいと思います。Bashソースを変更する必要がありますか、それとももっと簡単な方法(プラグインなど)がありますか?

4

6 に答える 6

3

まず第一に、bashソースをかなり大幅に変更する必要があります。何よりも、^>実装するのは本当に難しいからです。

bashリダイレクト演算子は通常、非常に単純な書き込みを行い、単一のファイル(またはパイプの場合はプログラム)でのみ機能することに注意してください。非常に具体的な解決策を除いて、通常、ファイルの先頭に書き込むことはできません。これは、書き込むたびに残りのすべてのコンテンツを前方に移動する必要があるという非常に単純な理由からです。それを試すこともできますが、それは難しく、非常に効果がなく(すべての書き込みでファイル全体を再書き込みする必要があるため)、非常に安全ではありません(エラーが発生すると、古いバージョンと新しいバージョンがランダムに混在することになります)。

そうは言っても、他の人が提案しているように、一時ファイルを使用する関数やその他のソリューションを使用したほうがよいでしょう。

完全を期すために、私自身の実装:

prepend() {
    local tmp=$(tempfile)
    if cat - "${1}" > "${tmp}"; then
        mv "${tmp}" "${1}"
    else
        rm -f "${tmp}"
        # some error reporting
    fi
}

@jpaの提案とは異なり、連結データを一時ファイルに書き込む必要があることに注意してください。その操作は失敗する可能性があり、失敗した場合は、元のファイルを失いたくないからです。その後、古いファイルを新しいファイルに置き換えるか、一時ファイルを削除して、任意の方法で障害を処理します。

概要は他のソリューションと同じです。

echo test | prepend file.txt

そして、パーミッションを保持し、シンボリックリンク(必要な場合)で安全にプレイするために少し変更されたバージョンは次のようになり>>ます:

prepend() {
    local tmp=$(tempfile)
    if cat - "${1}" > "${tmp}"; then
        cat "${tmp}" > "${1}"
        rm -f "${tmp}"
    else
        rm -f "${tmp}"
        # some error reporting
    fi
}

このバージョンは実際には安全性が低いことに注意してください。2番目の間にcat何か他のものがディスクに書き込んでいっぱいになると、ファイルが不完全になってしまうからです。

正直なところ、私は個人的には使用しませんが、必要に応じて、シンボリックリンクを処理し、アクセス許可を外部でリセットします。

于 2012-08-14T18:45:16.503 に答える
2

^履歴置換ですでに使用されているため、文字の選択は適切ではありません。


シェル文法に新しいリダイレクトタイプを追加するには、で開始しparse.yます。使用できるように新規として宣言し、出力(エラーメッセージなど)に表示されるよう%tokenに追加し、パーサーのルールを更新し、適切な文字に遭遇したときにこのトークンを発行するようにレクサーを更新します。STRING_INT_ALIST other_token_alist[]redirection

command.henum r_instruction拡張する必要があるリダイレクトタイプが含まれています。リダイレクション命令の処理には巨大なswitchステートメントがあり、実際のリダイレクションは全体の関数によって実行されます。残りのソースコード全体に散在しているのは、パイプラインを印刷、コピー、および破棄するためのさまざまな関数であり、これらも更新する必要がある場合があります。make_redirectionmake_cmd.credir.c

それで全部です!Bashはそれほど複雑ではありません。


これでは、先頭に追加するリダイレクトを実装する方法については説明していません。これは、UNIXファイルAPIが追加と上書きのみを提供するため、困難になります。ファイルの先頭に追加する唯一の方法は、ファイルを完全に書き直すことです。これは、(他の回答で言及されているように)既存のシェルリダイレクトよりもはるかに複雑です。

于 2012-08-14T19:55:47.580 に答える
1

演算子を追加するのはかなり難しいかもしれませんが、おそらく関数で十分でしょうか?

function prepend { tmp=`tempfile`; cp $1 $tmp; cat - $tmp > $1; rm $tmp; }

使用例:

echo foobar | prepend file.txt

「foobar」というテキストをfile.txtの前に追加します。

于 2012-08-14T18:30:24.293 に答える
0

ほとんどのLinuxファイルシステムはプリペンディングをサポートしていません。実際、安定したユーザースペースインターフェイスを備えている人は誰も知りません。したがって、他の人がすでに述べたように、必要に応じて、最初の部分だけ、またはファイル全体のいずれかを上書きすることだけに頼ることができます。

ファイルを切り捨てることなく、Bashの初期ファイルの内容を簡単に(部分的に)上書きできます。

    exec {fd}<>"$filename"
    printf 'New initial contents' >$fd
    exec {fd}>&-

上記$fdは、Bashによって自動的に割り当てられたファイル記述子$filenameであり、ターゲットファイルの名前です。Bashは、最初の行でターゲットファイルへの新しい読み取り/書き込みファイル記述子を開きます。これはファイルを切り捨てません。2行目は、ファイルの最初の部分を上書きします。ファイル内の位置が進むため、複数のコマンドを使用してファイル内の連続する部分を上書きできます。3行目は記述子を閉じます。各プロセスで使用できる数は限られているため、不要になった後で閉じる必要があります。そうしないと、長時間実行されるスクリプトが不足する可能性があります。

于 2012-08-14T21:37:41.660 に答える
0

bashのプラグインアーキテクチャ(「enable」組み込みコマンドを介して共有オブジェクトをロードする)は、追加の組み込みコマンドの提供に限定されていると思います。^>リダイレクト演算子は、単純なコマンドを実行するための構文の一部であるため、新しい演算子を認識して処理するには、パーサーを変更する必要があると思います。

于 2012-08-14T18:31:34.997 に答える
0

>予想よりも少ないことに注意してください。

  1. >リダイレクトを覚えて、コマンドラインから次の単語を削除します。
  2. コマンドラインが処理され、コマンドを起動してfork(2)(またはclone(2))を呼び出して、新しいプロセスを作成できる場合。
  3. コマンドに従って新しいプロセスを変更します。これには、変更された環境変数(SOMEVAR=foo yourcommand)だけでなく、変更されたファイル記述子も含まれます。この時点で、コマンドラインからのaは、書き込み専用モードでstdoutファイル記述子(つまり#1)でファイルがゼロバイトに切り捨て> yourfileられるという効果があります。Aは、ファイルが書き込み専用モードおよび追加モードのstdoutでoppendされるという効果があります。open(2)>> yourfile
  4. (今だけプログラムを起動します。execv(yourprogram, yourargs)

リダイレクトは、簡単な例として、次のように実装できます。

open(yourfile, O_WRONLY|O_TRUNC);

また

open(yourfile, O_WRONLY|O_APPEND);

それぞれ。

その後起動されたプログラムは、正しい環境がセットアップされ、fd1に問題なく書き込むことができます。ここから、シェルは関与しません。実際の作業はシェルではなく、オペレーティングシステムによって行われます。Unixにはプリペンドモードがないので(そしてその機能を正しく統合することは不可能です)、あなたが試みることができるすべては非常にひどいハックに終わるでしょう。

要件を再考してみてください。常に簡単な方法があります。

于 2012-08-15T10:04:33.070 に答える