perl -iをシンボリックリンクでなくする方法はありますか?


12

私の友人は、あなたがそうするなら:

perl -pi.bak -e 's/foo/bar/' somefile

「somefile」が実際にシンボリックリンクである場合、perlはドキュメントが行うと言っていることを実行します。

入力ファイルの名前を変更し、元の名前で出力ファイルを開き、その出力ファイルをprint()ステートメントのデフォルトとして選択することにより、これを行います。拡張子が指定されている場合、その拡張子を使用して、古いファイルの名前を変更し、バックアップコピーを作成します[...]

これにより、変更されていない実ファイルを指す新しいシンボリックリンク "somefile.bak"と、変更された新しい変更された通常ファイル "somefile"が作成されます。

多くの場合、シンボリックリンクをたどるのは望ましい動作です(たとえ.bakファイルの正しい場所があいまいなままであっても)。ラッパー内のシンボリックリンクをテストし、適切にケースを処理する以外に、これを行う簡単な方法はありますか?

sedそれが価値があることのために、同じことをします。)


1
vimまたはemacsを呼び出します(両方ともシンボリックリンクをたどると思います)。真剣に、答えは-p -iスクリプトで再実装することだと思います。
ジル 'SO-悪であるのをやめる'

少なくとも2009年6月にリリースされたバージョン4.2.1以降では、Sedは同じことをしません。シンボリックリンクを上書きするのではなく、リンク先のファイルを編集するには、編集に--follow-symlinksオプションを含める必要があります。 ; これは、古い動作に依存する可能性のある既存のスクリプトの破損を回避するために行われたと思われます。
ギャレット14

回答:


6

この場合、moreutilsの小さなsponge汎用ユーティリティ(「標準入力を取り込み、ファイルに書き込む」)が役立つかどうか、またシンボリックリンクに従うかどうかは疑問です。

著者は次の spongeように説明しています。

Unixツールでファイルをその場で編集する問題に対処します。つまり、出力を編集しようとしているファイルにリダイレクトするだけで、パイプラインの最初のコマンドの前にリダイレクトが有効になります(ファイルの内容を上書き)ファイルからの読み取りに進みます。以下のようなスイッチsed -iperl -iあなたがパイプラインで使用する場合がありますこの問題を回避ではなく、すべてのコマンドは、このようなオプションがあり、あなたはとにかく、複数のコマンドパイプラインとそのアプローチを使用することはできません。

私は通常、このように少しスポンジを使用します:

sed '...' file | grep '...' | sponge file

ちょっとクール、それは動作します。上記のGillesのコメントは「本当の」答えだと思いますが、彼は答えとしてそれを作らなかったので、私は新しいユーティリティを学んだので、これを取り上げます。:)
mattdm

しかしsponge、実際にそのような使用法についてテストしましたか?私に関しては、まだです。ここで必要な方法でテストで動作したかどうかを示すコメントを残してください。ああ、コメントが表示されます。確認していただいてありがとうございます!
imz-イヴァンザカリヤシェフ

—はい、返信する前に試しました。ときにfileあなたの例では上記のシンボリックリンクで、リンクが放置され、実際のファイルが変更されました。
mattdm

@mattdm:はい、確認ありがとうございます!(私がコメントを書いたよりも少し遅れてあなたの言葉が「うまくいく」ことに気づいた。)
imz-イヴァンザカリヤシェフ

3

somefileシンボリックリンクであるという事実を知っている場合、次のように明示的にファイルへのフルパスを指定できます。

perl -pi.bak -e 's/foo/bar/' $(readlink somefile)

この方法では、元のファイルで置換が直接行われるため、元のシンボリックリンクはそのまま残ります。


しかし、の出力はreadlinkまだ別のシンボリックリンクである可能性があります。ベストは、使用するのだろう-fか、-e利用可能な場合やzshさん$file:P(:P)グロブ修飾子@ikegamiによって示されるようにシンボリックリンクフリーパスを取得します。
ステファンシャゼル

3

単一のファイルを扱っている場合、コマンドは次のようになります。

perl -i -pe'...' -- "$qfn"

その場合の解決策は次のとおりです。

perl -i -pe'...' -- "$( readlink -e -- "$qfn" )"

これは、シンボリックリンクと非シンボリックリンクの両方を処理します。


任意の数のファイルを処理している場合、コマンドは次のようになります。

... | xargs -r perl -i -pe'...' --

その場合の解決策は次のとおりです。

... | xargs -r readlink -ze -- | xargs -r0 perl -i -pe'...' --

これは、シンボリックリンクと非シンボリックリンクの両方を処理します。


警告 readlinkは標準コマンドではないため、存在、引数、および機能はシステムによって異なるため、必ずドキュメントを確認してください。たとえば、一部の実装には-f(ここでも使用できます)がありますが、そうでない-eものもあります。はGNU busyboxreadlink -fように動作しますreadlink -e。また、一部のシステムでは、realpathコマンドの代わりにreadlink一般的にGNUのように動作しますreadlink -f

GNU readlink -eでは、既存のファイルに解決できないシンボリックリンクが静かに削除されることに注意してください。


@StéphaneChazelas、私に$var:Pは役に立たない。(X='tmp' zsh -c 'perl -E"say for @ARGV" $X:P'出力tmp:P
池上

にはzsh 5.3(2016)以上が必要です$var:P。古いバージョンでは、$var:A代わりにいつでも使用できます。違いについてはマニュアルを、導入の理由についてはzsh.org/mla/users/2016/msg00593.htmlを参照してください:P(実際のrealpath()インターフェース)。
ステファンシャゼラス

:A4.3.10(2009)で追加されreadlink -z、2012年にGNU でreadlink、サポートする他の実装を認識していません-z)。GNU xargsでは-r、入力が空にならないことを保証できない限り、通常はオプションが必要なことに注意してください。ここでは、大したことではありません(perlコードにBEGIN/ ENDステートメントが含まれていない限り)-i used with no filenames on the command line, reading from STDIN.。その場合、警告が表示されます。
ステファンシャゼル

おっと、-rドキュメントを読み間違えました。私はそれがすることの反対をしたと思った。再装備。
池上
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.