同じ行番号を持つディレクトリ内のすべてのファイルを削除する方法は?

同じ行番号を持つディレクトリ内のすべてのファイルを削除する方法は?

ディレクトリ内のすべての.fastaファイルから151から154行を削除したいと思います。頑張ってる

find . -type f -exec sed -i.fix '151,154d' '{}' '+' 

ただし、他の400ファイルではなく、最初のファイルでのみ実行されます。

答え1

-i非標準sedオプションです。それはから来るperl。 GNUとFreeBSDは、sed動作をエミュレートするために2001年末と2002年初めに独立して追加されましたが、インターフェースは異なります。より多くの変更(特に元のファイルメタデータが保持される程度に関して)があったので、より多くの実装が行われました。-iperl

では、perl次の操作を行います。

perl -ni.back -e 'print unless $. == 151..154' file

$.現在行番号です現在の入力ファイルハンドル。 /を使用すると、<>引数として渡されたファイルごとにファイルハンドルが開きますが、各ファイル間で閉じられないため、各ファイル間でリセットされません。これを行うには、次のものが必要です。-nARGVARGV$.

perl -ni.back -e '
  print unless $. == 151..154;
  close ARGV if eof' file1 file2

GNUは、à laオプション(2001-09-25に追加されましたが、1年後(3.95)までリリースされていません)を追加したsed最初の実装(AFAIK)でした。このオプションは、各ファイル間の行番号をリセットします(他のGNU拡張を意味します)。 。-iperl-s

FreeBSD別のことをしました。。 GNUの元のAPIとFreeBSDの主な違いは、-iFreeBSDではパラメータが必須であるのに対して、GNUではsed同様のオプションですperl。 FreeBSDでは、最初は各ファイル間の行番号はリセットされません。

2007年、FreeBSDはsed2番目の点でGNUと一致します。。各ファイル間の行番号がリセットされ-Iました-i

-iBusybox、NetBSD、OpenBSDなどの他の実装によってはるかに後でサポートが追加されsedましたが、sed両方の点でGNUと一致します。

macOSはsed以前のバージョンのFreeBSDに基づいているため、現在のバージョンのFreeBSDと同じように動作する唯一の実装である可能性があり、現在使用されている実装かもしれません。

したがって、ここでは次のものを使用する必要がありますperl

find . -type f ! -name '*.back' -exec perl -ni.back -ne '
  print unless $. == 151..154;
  close ARGV if eof' {} +

または、sed各ファイルに対して1つずつ呼び出します。

find . -type f ! -name '*.back' -exec sed -i.back 151,154d {} \;

sedGNUまたはGNUをインストールして使用するかawk(代わりに-i /usr/share/awk/inplace.awk1を使用して一致)、またはFNRNRed/ex方法に応じて


^使用しないでください-i inplace現在の作業ディレクトリから最初に拡張機能をgawkロードしようとすると、誰かがそのディレクトリにマルウェアを植えた可能性があります。システムに付属の拡張プログラムのパスは異なる場合があります。出力を参照してください。inplaceinplaceinplace.awkinplacegawkgawk 'BEGIN{print ENVIRON["AWKPATH"]}'

答え2

この答えは実際の内部編集ではないので、ex代わりに使用されます。一時ファイルに書き込んでから名前を変更して元のファイルを置き換えるため、inode番号が変更されます。これにより、COWファイルシステム(btrfsやzfsなど)のすべてのハードリンク、およびスナップショットとファイルのinode番号に依存するすべてのエントリが破損します。他の実装/オプション( 'sオプションを含む)を使用する他のほとんどの一般的なコマンドでも同様です。sed -ised -i-i--in-placeperl-i

find . -type f -exec sh -c 'for f in "$@" ; do
    cp -a "$f" "$f.fix"
    printf "%s\n" 151,154d x | ex -s -- "$f" 
  done' sh {} +

このブランチは、sh見つかったファイルのリストを処理するために使用されますfind

このshプロセスでは、最初に元のファイルのバックアップコピーを作成し(タイムスタンプや権限などのすべての属性を保存するためにGNUオプションを使用して)、呼び出してcpファイルを編集します。-aex

上記のパイプラインのprintf ... | ex ...2つのexコマンド(*)into では、ex各コマンドは改行文字で区切られます。最初のコマンドは行151-154を削除します。 2番目(x)はex変更をファイルに書き込むように指示します(ex保存するように指示しない限り、デフォルトでは保存せずに終了します)。変更がなければ、保存せずに終了します。と同じコマンドですx:xvi

注:単一の入力ファイルの行数が154未満の場合いいえこのファイルが変更されます。

この-sオプションはex静かで診断メッセージを印刷しないように指示します。

ファイル名がで始まる場合は、--ファイル名引数がオプションとして解釈されないようにしてください。このコマンドで出力されるすべてのファイル名にはプレフィックスがあるため、ここでは必ずしも必要ではありません。ただし、これは無害で不明なファイル名を処理するのに良い習慣です。ex-find./

(*) exCommandはcommandとほぼ同じですsed。ご存知のとおり、昔edsed..ビジュアル編集モードが追加されましたが、コマンドモードのコマンドは保持されていました。ここで使用するモードであるビジュアルモードを使わずに、コマンドモード編集のように実行することもできます。それでも、ほとんどはレプリカですが、最初に書かれてから数十年間、オリジナルと比較して少しの改善(例:コマンド)が得られました。edviedvied:viexexedxed

答え3

あなたは正しい道を行っています。コマンドを少し編集するだけです。 execの代わりにxargsを使用することもできます。動作するバージョンは次のとおりです。

$ find . -type f | xargs -I{} sed -i '151,154d' {}

関連情報