私のフォルダには名前にスペースを含む11個のファイルがありますが、最新の10個のファイルをコピーしたいと思います。以前は、ls -t | head -n 10
最新の10個のファイルしかインポートできませんでした。 cpステートメントで式を使用しようとすると、名前にスペースが含まれているため、ファイルが見つからないというエラーが発生します。
たとえば、次のようにcp: cannot stat ‘10’: No such file or directory
なります。10 abc.pdf
CPドア:cp $(ls -t | head -n 10) ~/...
どのように動作させることができますか?
答え1
Bashを使用していて100%安全な方法が必要な場合(ファイル名に注意する必要がある難しい方法を学んだので、あなたも欲しいと思います)、次のことができます。
shopt -s nullglob
while IFS= read -r file; do
file=${file#* }
eval "file=$file"
cp "$file" Destination
done < <(
for f in *; do
printf '%s %q\n' "$(date -r "$f" +'%s')" "$f"
done | sort -rn | head -n10
)
そのうちのいくつかを見てみましょう。
for f in *; do
printf '%s %q\n' "$(date -r "$f" +'%s')" "$f"
done
これは、フォームの標準出力用語で印刷されます。
Timestamp Filename
ここで、タイムスタンプはエポック(-r
オプションで得られたdate
)以降の変更日(秒)で、ファイル名は引用されたファイル名のバージョンです。シェル入力で再利用可能(フォーマット指定子を参照してくださいhelp printf
)%q
。次に、行を数字順、逆順に並べ替え、sort
最初の10行だけを保持します。
while
次にループに供給します。タイムスタンプは割り当てfile=${file# *}
(最初のスペースの前のすべてのエントリを削除)として削除され、明らかに危険な行にはeval "file=$file"
エスケープ文字が削除され、printf %q
最後にファイルを安全にコピーできます。
おそらく最善のアプローチや実装ではないかもしれませんが、可能なすべてのファイル名に対して100%の安全性が保証され、作業が完了します。ただし、これは通常のファイル、ディレクトリなどを同じように扱います。通常のファイルに制限するには、[[ -f $f ]] || continue
このfor f in *; do
行の後に追加してください。また、隠しファイルは考慮しません。ファイルを隠すには(もちろんそうでは.
ありません..
)shopt -s dotglob
。
もう1つの100%Bashソリューションは、Bashを直接使用してファイルをソートすることです。クイックソートの使用方法は次のとおりです。
quicksort() {
# quicksorts the filenames passed as positional parameters
# wrt modification time, newest first
# return array is quicksort_ret
if (($#==0)); then
quicksort_ret=()
return
fi
local pivot=$1 oldest=() newest=() f
shift
for f; do
if [[ $f -nt $pivot ]]; then
newest+=( "$f" )
else
oldest+=( "$f" )
fi
done
quicksort "${oldest[@]}"
oldest=( "${quicksort_ret[@]}" )
quicksort "${newest[@]}"
quicksort_ret+=( "$pivot" "${oldest[@]}" )
}
その後、それらをソートして上位10個を保持してからターゲットにコピーします。
$ shopt -s nullglob
$ quicksort *
$ cp -- "${quicksort_ret[@]:0:10}" Destination
以前の方法と同様に、通常のファイル、ディレクトリなどを同じように処理し、隠しファイルをスキップします。
別のアプローチ:およびパラメータがls
ある場合は、次のものを使用できます。i
q
ls -tiq | head -n10 | cut -d ' ' -f1 | xargs -I X find -inum X -exec cp {} Destination \; -quit
これにより、ファイルの inode が表示され、find
その inode が参照するファイルからコマンドを実行できます。
繰り返しますが、これは通常のファイルだけでなくディレクトリなども処理します。ls
出力形式に依存しすぎるので、これはあまり好きではありません...
答え2
ディレクトリ内のすべてのファイルグループに対して、常に最も古いファイルを無視します。
less_oldest() {
while [ -e "$1" ] ; do
for f do [ "$f" -ot "$1" ] && break
done && { set -- "$@" "$1"
shift ; continue
} ; shift ; break
done
printf '///%s///\n' "$@" |
sed "s|'"'|&"&"&|g;'"s|///|'|g"
}
これは完全に移植可能で、返すことができる文字に関係なく、シェル安全ファイル名の配列を印刷します。あなたの場合はdro poneだけが必要なので、次のように一度だけ実行してください。
{ printf 'cp -t ~"/..."'
less_oldest "${dir_of_11_files}/"*
} | sh