リストで最後に変更され、ファイル拡張子が.gzで終わる最後のN行を除外します。

リストで最後に変更され、ファイル拡張子が.gzで終わる最後のN行を除外します。

findAIXでは、このコマンドを使用して次に終わるファイルを除外し、.gzリストから最後の2行も除外する必要があります。たとえば、ディレクトリには次のものがあります。

shop14_0_Log0002019754.gz
shop14_0_Log0002019755.gz
shop14_0_Log0002019756.gz
shop14_0_Log0002019757
shop14_0_Log0002019758.gz
shop14_0_Log0002019759.gz
shop14_0_Log0002019760.gz
shop14_0_Log0002019761.gz
shop14_0_Log0002019762

圧縮されていないファイルのみを検索し、下部の最後の2つのファイルを除いて以下のような出力を取得したいと思います。

出力コマンドは次に到達する必要があります。

shop14_0_Log0002019757

そのコマンドを使用して最後の2行を除外できますが、ls名前で終わるファイルを除外するにはどうすればよいですか.gz? AIX / UNIXでこれを行う方法を見つけようとしています。

ls -ltr | awk '{print $9} |  sed '$d' |  sed '$d'

を使用すると、リストから除外して圧縮されていないファイルのリストをfind取得できますが、.gzこれには不要な最後の2つのファイルが含まれています。

find . -type f ! -name '*\.gz'  -print 

上記findのコマンドは以下を返します。

./shop14_0_Log0002019757
./shop14_0_Log0002019762

そのファイルはshop14_0_Log0002019762リストから除外する必要がありshop14_0_Log0002019761、圧縮されていない場合でもリストから除外する必要があります。

除外する「最後の2つ」の項目は、ファイル変更時間に基づいてソートされます。私の究極の目標は、圧縮されていないファイルを圧縮することです。

どうすればいいですか?

答え1

Bashを使用していて、ファイル名に改行や空白が含まれていないことを100%確信している場合は、次のようにします。

shopt -s extglob
ls -t !(*gz) | tail -n +3 | while IFS= read -r file; do gzip "$file"; done

拡張ワイルドカードを有効にして「gzで終わらない」をshopt -s extglob提供します。!(*gz)次に、を使用して、ls -t変更時刻に基づいて最新の項目からソートします。これは、tail -n +3「3行目から始まるすべてのコンテンツを印刷する」という意味なので、最初の2つのファイルはスキップされます。最後に、ファイルのループwhileにパイプします。gzipまたは、次のことができます。

gzip $(ls -t !(*gz) | tail -n +3)"

または

ls -t !(*gz) | tail -n +3 | xargs gzip

これは、ファイル名が正しいことを確認できる場合にのみ機能します。バラよりhttps://mywiki.wooledge.org/ParsingLsls解析された出力が推奨されない理由

答え2

.gz最後の2つのファイルを削除する前または後にファイルを除外する必要があるかどうかはわかりません。以前の例では、2つのファイルしか残っておらず、両方を省略する必要があるため、出力は空ですが、shop14_0_Log0002019757「以降」を想定して操作を解決しました。

解決策1、強く押す:

#!/bin/bash

files=(*)
newest_1=${files[0]}
newest_2=${files[0]}

for f in "${files[@]}"; do
  if [[ $f -nt $newest_1 ]]; then
    newest_2=$newest_1
    newest_1=$f
  elif [[ $f -nt $newest_2 ]]; then
    newest_2=$f
  fi  
done

if [[ $newest_1 == "$newest_2" ]]; then
    filenames=$newest_1
else
    filenames="${newest_2}\n${newest_1}"
fi
   
echo -e "$filenames" | sed '/\.gz$/d'

解決策2:AIXでは、デフォルトでは使用できないGNUユーティリティーを使用してください。ただし、これは方法を実証するのに役立ちます。

find . -maxdepth 1 ! -name '.' -printf "%A@ %f\n" | sort -g | head -n -2 | cut -d' ' -f2 | sed '/\.gz/d'

説明する

  • find .- 現在のディレクトリで検索
  • -maxdepth 1- 再帰なし、レベル1のみ
  • ! -name '.'- 現在のディレクトリエントリを除く(.
  • -printf "%A@ %f\n" |- 小数部とファイル名を含む1970年以降のファイルの最後のアクセス時間を秒単位で出力します。
  • sort -g |- 浮動小数点数でソート
  • head -n -2 |- 最後の2行を除くすべての行出力
  • cut -d' ' -f2 |- 最初の列だけを切り取り、ファイル名を保持します。
  • sed '/\.gz$/d'.gz- ファイルの削除。

答え3

findコマンドの使用を好むと仮定すると、次のように問題が解決される可能性があります。

find . -type f ! -name '*\.gz' -print | awk '{Q[N++]=$0; N=N%3; if (Q[N]!="") {print Q[N]}}

awkコマンドは、長さnの配列Qを埋めます。

  • 質問してください[N++]

配列を介してモジュロ3に進みます(配列が長いほど、より多くの要素をスキップできます)。

  • N=N%3

以前に埋められた挿入された2つの項目を印刷します(したがって、最後の2つは無視されます)。 if は、配列が完全に初期化されていない場合、最初の挿入をスキップします。

123   123   123   123   123  ...
^^     ^^   ^ ^   ^^     ^^
||     ||   | |   ||     ||
io     io   O i   iO     iO
nu     nu   U n   nU     nU
 t      t   T      T      T

"ls"を使用したい場合は、$ 0をn番目の要素に変更できます(この場合、ファイル名にスペースを含めないでください)。あなたが経験している問題の極端なケースを私が完全に理解しているかどうかわからないので、確認してください。

答え4

ksh93シェル(最新のAIXバージョンの標準)を使用して配列をサポートし、ファイルが変更時の順序で拡張されると仮定すると(つまり、ファイル名の順序が変更のタイムスタンプと同じ順序を表す)、ファイル全体を取得できます。配列リストを使用し(後で「最後の2つ」を抽出するのに役立ちます)、別の配列を使用して圧縮されていないすべてのファイルを見つけます。最終ファイルのリストは、圧縮されていないファイルのリストを繰り返し、以前の「最後の2つ」と一致するすべてのファイルを削除することによって収集されます。

#!/usr/bin/ksh93

files=(*)
uncompressed=( !(*.gz) )

for index in "${!uncompressed[@]}"
do
  if [[ "${uncompressed[index]}" == "${files[-1]}" ]] || \
     [[ "${uncompressed[index]}" == "${files[-2]}" ]]
  then
    unset -v 'uncompressed[index]'
  fi
done

# echo gzip "${uncompressed[@]}"

最後に「uncompressed」という配列があります。示されているように、これらのファイル名を圧縮できます(remove echo)。

関連情報