次のような名前のファイルがたくさんあります。
name_file-1.txt
name_file-2.txt
name_file-3.txt
some_other_file-1.txt
some_other_file-2.txt
何千もの異なるファイル名があり、いくつか-1.txt
は最後に1つだけあり、いくつか-1.txt
は-2.txt
...-60.txt
各ファイルの最大数をコピーする必要があるためname_file-3.txt
、some_other_file-2.txt
。 Linuxコマンドラインでこれをどのように実行しますか?
答え1
そしてzsh
:
typeset -A greatest
for f (*-*(n)) greatest[${f%-*}]=$f
cp -- $greatest /destination
*-*(n)
-
:名前に(*-*
)が含まれており、番号でソートされた非表示のファイル((n)
glob修飾子)。${f%-*}
:ファイル名の一部、右まで-
(またはなければ最後まで-
)。$greatest
:空でない状態に展開されます。価値連想配列。したがって、ここでは、同じルートディレクトリを共有するファイルの場合、最も高い番号のファイルのみが拡張されます。
答え2
files=(*)
mapfile -t prefixes < <(printf "%s\n" "${files[@]%-*}" | sort -u)
for p in "${prefixes[@]}"; do ls -v "$p"* | tail -1; done
name_file-3.txt
some_other_file-2.txt
その後、別のディレクトリにコピーします。
for ...; done | xargs cp -t /destination/directory
答え3
次のPOSIX互換パイプは、ファイルが現在の作業ディレクトリにあり、その名前が例(ダッシュの前にある数字)と一致する場合に機能するはずです。
ls | sort -t- -k1,1 -k2,2rn | awk -F- 'k!=$1 {print; k=$1}' | pax -rw /path/to/dir
sortの-uオプションが安定している場合、awkコンポーネントはsort -uに置き換えることができます(したがって、セットの最初の行は常にセットを表すように選択されます)。 POSIXはこの安定性を必要としませんが、マニュアルによれば、{Free、Net、Open}BSDおよびGNUの実装がこれを提供します。誘惑する運命が好きなら:
ls | sort -t- -k1,1 -k2,2rn | sort -mut- -k1,1 | pax -rw /path/to/dir
どちらの場合も、現在の作業ディレクトリにターゲットディレクトリが見つかりません。
答え4
より信頼性が高くカスタマイズ可能なファイル名を解析するために、ファイルをタブ区切りに分割し、awkを使用して各部分の上位ランクを見つけて報告しました。次のステップに進む前に、パイプラインの各部分を試してください。
find DIR -type f <other find criteron> -print |
perl -lne 'print join("\t",(/^(.*?-)(\d+)(\.\w+)$/))' |
awk -F\\t '$2 > f[$1] { f[$1]=$2;e[$1]=$3; } END { for (k in f) { print k f[k] e[k] }}' |
xargs cp -t <desination_directory>
awkスクリプトは各ファイル名を関連する配列エントリに入れ、常に見つかった最高のランクを維持します。拡張は独自の配列に保存されます。すべての入力が処理された後、すべての配列項目が1行に1つずつ出力されます。このxargs cp -t
行は、すべてのファイルを指定したディレクトリにコピーします。
別の方法があります動作しません数字が9より大きく、0で埋められていない場合は問題ありません。この方法では、ファイルをアルファベット順に並べ替えてからリストを解析すると、最初に表示されたファイル名を使用して最初の部分が変更されます。ファイル名が次のような場合は機能しません。
file-9.txt
file-10.txt
file-10.txtがfile-9の前に表示されるためです。上記のawkスクリプトは数値比較を実行します。
注:タブと改行を含むファイル名はブロックを引き起こす可能性があります。
注2:各ファイル名のプレフィックスに複数の拡張子がある場合は、正しい拡張子を得るためにいくつかの調整を行う必要があります。