ディレクトリにファイル名で並べられたファイルがたくさんあります。最後のN(たとえば、N = 4)ファイルをホームディレクトリにコピーします。どうすればよいですか?
cp ./<the final 4 files> ~/
これは、bash/ksh93/zsh配列で簡単に実行できます。
_a=(*)
cp -- "${a[@]: -4}" ~/
_
これは、スペース、タブ、改行、またはその他の難しい文字が含まれている場合でも、すべての非表示ではないファイル名で機能します(現在のディレクトリにbash
を含む非表示でないファイルが少なくとも4つあると想定)。
a=(*)
これにより、すべてのファイル名を含む配列a
が作成されます。 bashによって返されるファイル名はアルファベット順にソートされます。 (これは"ファイル名順"の意味だと思います)
_${a[@]: -4}
_
これは、配列a
の最後の4つの要素を返します(配列にbash
のある要素が少なくとも4つ含まれている場合)。
_cp -- "${a[@]: -4}" ~/
_
これにより、最後の4つのファイル名がホームディレクトリにコピーされます。
これにより、最後の4つのファイルがホームディレクトリにのみコピーされ、同時にコピーされたファイルの名前の前に文字列_a_
_が追加されます。
_a=(*)
for fname in "${a[@]: -4}"; do cp -- "$fname" ~/a_"$fname"; done
_
a=(./some_dir/*)
の代わりにa=(*)
を使用すると、ファイル名にディレクトリが添付されるという問題があります。 1つの解決策は次のとおりです。
_a=(./some_dir/*)
for f in "${a[@]: -4}"; do cp "$f" ~/a_"${f##*/}"; done
_
別の解決策は、サブシェルを使用し、サブシェルのディレクトリにcd
を使用することです。
_(cd ./some_dir && a=(*) && for f in "${a[@]: -4}"; do cp -- "$f" ~/a_"$f"; done)
_
サブシェルが完了すると、シェルは元のディレクトリに戻ります。
この質問では、「ファイル名で並べ替えられた」ファイルを要求します。その順序は、Olivier Dulacがコメントで指摘しており、ロケールによって異なります。マシン設定に関係なく結果を修正することが重要な場合は、配列a
を定義するときにロケールを明示的に指定するのが最善です。例えば:
_LC_ALL=C a=(*)
_
locale
コマンドを実行すると、現在のロケールを確認できます。
zsh
を使用している場合は、括弧()
を使用して、必要なファイルを選択する、いわゆるglob qualifiersのリストを囲むことができます。あなたの場合、それは
cp *(On[1,4]) ~/
ここでOn
はファイル名をアルファベット順で逆順に並べ替え、[1,4]
はそれらのうち最初の4つだけを取ります。
.
を使用してプレーンファイル(ディレクトリ、パイプなどを除く)のみを選択し、--
をcp
コマンドに追加して、 -
で正しく始まるので、
cp -- *(.On[1,4]) ~
隠しファイル(ドットファイル)も考慮したい場合は、D
修飾子を追加します。
cp -- *(D.On[1,4]) ~
これは、非常に単純なbashコマンドを使用したソリューションです。
find . -maxdepth 1 -type f | sort | tail -n 4 | while read -r file; do cp "$file" ~/; done
説明:
find . -maxdepth 1 -type f
現在のディレクトリですべてのファイルを検索します。
sort
アルファベット順にソートします。
tail -n 4
最後の4行のみを表示します。
while read -r file; do cp "$file" ~/; done
コピーコマンドを実行する各行をループします。
シェルの並べ替えが適切である限り、次のことを実行できます。
_set -- /path/to/source/dir/*
[ "$#" -le 4 ] || shift "$(($#-4))"
cp "$@" /path/to/target/dir
_
これは、提供されているbash
固有の配列ソリューションと非常に似ていますが、POSIX互換のシェルに移植できる必要があります。両方の方法に関する注意事項:
_cp --
_を使用してcp
引数を指定するか、各名前の先頭に_.
_ドットまたは_/
_のいずれかを取得することが重要です。これを実行しないと、cp
の最初の引数で先頭の_-
_ダッシュがリスクになり、オプションとして解釈され、操作が失敗するか、意図しない結果がレンダリングされる可能性があります。
set -- ./*
_またはarray=(./*)
のように簡単に実行できます。両方のメソッドを使用するときは、少なくともarg配列に削除しようとする数と同じ数の項目があることを確認することが重要です。ここでは、数学の拡張を使用しています。 shift
は、arg配列に少なくとも4つの項目がある場合にのみ発生し、4の余剰になる最初の引数のみをシフトします。
set 1 2 3 4 5
_の場合は_1
_をシフトしますが、_set 1 2 3
_の場合は何もシフトしません。a=(1 2 3); echo "${a[@]: -4}"
は空白行を出力します。あるディレクトリから別のディレクトリにコピーする場合は、pax
を使用できます。
_set -- /path/to/source/dir/*
[ "$#" -le 4 ] || shift "$(($#-4))"
pax -rws '|.*/|new_prefix|' "$@" /path/to/target/dir
_
...コピーすると、すべてのファイル名にsed
スタイルの置換が適用されます。
ファイルのみがあり、その名前に空白や改行が含まれていない(そして$IFS
が変更されていない)か、グロブ文字(またはls
の一部の実装で印刷できない文字)である場合、および.
で始めないでください。これを行うことができます:
cp -- $(ls | tail -n 4) ~/
これは、ループコードのない単純なbashソリューションです。最後の4つのファイルを現在のディレクトリから宛先にコピーします。
$ find . -maxdepth 1 -type f |tail -n -4|xargs cp -t "$destdir"