web-dev-qa-db-ja.com

ディレクトリからすべてのファイルの最後の行を削除する方法は?

ディレクトリに多数のテキストファイルがあり、ディレクトリ内のすべてのファイルの最後の行を削除したい。

どうすればできますか?

17

vimにアクセスできる場合は、以下を使用できます。

for file in ./*
do
  if [ -f "${file}" ]
  then
    vim -c '$d' -c "wq" "${file}"
  fi
done
4
R Sahu

GNU sedがある場合は、この素敵なワンライナーを使用できます。

 sed -i '$ d' ./*

現在のディレクトリにある非表示ではない各ファイルの最後の行を削除します。スイッチ-i for GNU sedは所定の位置で動作することを意味し、'$ d'sedに最後の行($は最後を意味し、dは削除を意味します)。

16
StefanR

ディレクトリに通常のファイル以外のものが含まれている場合、またはファイル名にスペース/改行が含まれているファイルがある場合、他のすべての回答に問題があります。関係なく機能するものは次のとおりです。

find "$dir" -type f -exec sed -i '$d' '{}' '+'
  • find "$dir" -type f$dir ディレクトリでファイルを検索します
    • -type fこれは通常のファイルです。
    • -exec見つかった各ファイルに対してコマンドを実行します
    • sed -i:ファイルを編集します。
    • '$d':最後の($)行を(d)削除します。
    • '+'sedに引数を追加し続けるようにfindに指示します(@zwolのおかげで、ファイルごとにコマンドを個別に実行するよりも少し効率的です)。

サブディレクトリに降りたくない場合は、引数-maxdepth 1findに追加できます。

11
N.I.

GNU sed -i '$d'は、ファイル全体を読み取り、最後の行なしでそのコピーを作成することを意味しますが、(少なくとも大きなファイルの場合)ファイルを切り捨てるだけの方がはるかに効率的です。

GNU truncateを使用すると、次のことができます。

for file in ./*; do
  [ -f "$file" ] &&
    length=$(tail -n 1 "$file" | wc -c) &&
    [ "$length" -gt 0 ] &&
    truncate -s "-$length" "$file"
done

ファイルが比較的小さい場合は、ファイルごとにいくつかのコマンドを実行するため、効率が低下する可能性があります。

最後の改行文字の後(最後の行の後)に余分なバイトが含まれているファイルの場合、つまり、区切りのない最後のlineがある場合、tail実装、tail -n 1は、これらの余分なバイト(GNU tailなど)、または最後の(適切に区切られた)行とそれらの余分なバイトのみを返します。

9

よりポータブルなアプローチ:

for f in ./*
do
test -f "$f" && ed -s "$f" <<\IN
d
w
q
IN
done

dはデフォルトで最後の行を選択するため、この場合はed$dと同じであることを除いて、これには説明は必要ないと思います。
これは再帰的に検索せず、隠しファイル(別名dotfiles)を処理​​しません。
これらも編集したい場合は、 ディレクトリ内の隠しファイルと*を照合する方法をご覧ください

6
don_crissti

ドットファイルを含む、現在のディレクトリから再帰的に始まるすべてのファイル用のPOSIX準拠のワンライナー:

find . -type f -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +

ために .txtファイルのみ、非再帰的に:

find . -path '*/*/*' -Prune -o -type f -name '*.txt' -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +

こちらもご覧ください:

3
Wildcard