find
AIXでは、このコマンドを使用して次に終わるファイルを除外し、.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
)。