Bashでは、特定のパターンに一致する最新のファイルのファイル名を返す関数を作成したいと思います。たとえば、次のようなファイルのディレクトリがあります。
Directory/
a1.1_5_1
a1.2_1_4
b2.1_0
b2.2_3_4
b2.3_2_0
「b2」で始まる最新のファイルが必要です。bashでこれを行うにはどうすればよいですか?これを~/.bash_profile
スクリプトに含める必要があります。
Bashでは、特定のパターンに一致する最新のファイルのファイル名を返す関数を作成したいと思います。たとえば、次のようなファイルのディレクトリがあります。
Directory/
a1.1_5_1
a1.2_1_4
b2.1_0
b2.2_3_4
b2.3_2_0
「b2」で始まる最新のファイルが必要です。bashでこれを行うにはどうすればよいですか?これを~/.bash_profile
スクリプトに含める必要があります。
回答:
ls
このコマンドは、パラメータがある-t
時間でソートすることを。次に、最初の(最新の)をで取得できhead -1
ます。
ls -t b2* | head -1
しかし注意してください:なぜlsの出力を解析すべきではないのですか?
私の個人的な意見:解析ls
は、ファイル名にスペースや改行などの面白い文字が含まれている場合にのみ危険です。ファイル名に変な文字が含まれないことが保証できる場合、解析ls
は非常に安全です。
多くのシステムの多くの人がさまざまな状況で実行することを意図したスクリプトを開発している場合は、解析しないことをお勧めしますls
。
「正しい」方法は次のとおりです。ディレクトリ内の最新(最新、最も古い、最も古い)ファイルを見つけるにはどうすればよいですか?
unset -v latest
for file in "$dir"/*; do
[[ $file -nt $latest ]] && latest=$file
done
ls
、printf "%s\n" b2* | head -1
あなたのためにそれを行います。
b2.10_5_2
このソリューションは無効になります。
組み合わせfind
とはls
適しています
ソリューション:
find . -name "my-pattern" -print0 |
xargs -r -0 ls -1 -t |
head -1
分解してみましょう:
ではfind
、次のようにすべての興味深いファイルを照合できます。
find . -name "my-pattern" ...
次に-print0
、次のls
ようにすべてのファイル名を安全に渡すことができます:
find . -name "my-pattern" -print0 | xargs -r -0 ls -1 -t
追加のfind
検索パラメーターとパターンをここに追加できます
find . -name "my-pattern" ... -print0 | xargs -r -0 ls -1 -t
ls -t
変更時刻(新しいものが最初)でファイルをソートし、1行に1つずつ出力します。-c
作成時間で並べ替えることができます。注:これは改行を含むファイル名で壊れます。
最後head -1
に、ソートされたリストの最初のファイルを取得します。
注: xargs
引数リストのサイズにはシステム制限を使用してください。このサイズを超えると、複数回xargs
呼び出されls
ます。これはソートを壊し、おそらく最終的な出力も壊します。走る
xargs --show-limits
システムの制限を確認します。
注2:find . -maxdepth 1 -name "my-pattern" -print0
サブフォルダーを介してファイルを検索しない場合に使用します。
注3: @starfry-で指摘されているように、によって一致するファイルがない場合、の-r
引数xargs
はの呼び出しを妨げてls -1 -t
いますfind
。提案ありがとうございます。
find . -name "my-pattern" ... -print0
私に与えるfind: paths must precede expression: `...'
...
「その他のパラメータ」の略です。必要なければ、省略してください。
-r
、標準入力で何も受信しない場合にコマンドラインを実行しないようにxargsに指示するxargsコマンドラインに追加することです。
-r
答えを追加しました。
これは、必要なBash関数の可能な実装です。
# Print the newest file, if any, matching the given pattern
# Example usage:
# newest_matching_file 'b2*'
# WARNING: Files whose names begin with a dot will not be checked
function newest_matching_file
{
# Use ${1-} instead of $1 in case 'nounset' is set
local -r glob_pattern=${1-}
if (( $# != 1 )) ; then
echo 'usage: newest_matching_file GLOB_PATTERN' >&2
return 1
fi
# To avoid printing garbage if no files match the pattern, set
# 'nullglob' if necessary
local -i need_to_unset_nullglob=0
if [[ ":$BASHOPTS:" != *:nullglob:* ]] ; then
shopt -s nullglob
need_to_unset_nullglob=1
fi
newest_file=
for file in $glob_pattern ; do
[[ -z $newest_file || $file -nt $newest_file ]] \
&& newest_file=$file
done
# To avoid unexpected behaviour elsewhere, unset nullglob if it was
# set by this function
(( need_to_unset_nullglob )) && shopt -u nullglob
# Use printf instead of echo in case the file name begins with '-'
[[ -n $newest_file ]] && printf '%s\n' "$newest_file"
return 0
}
Bashビルトインのみを使用し、改行やその他の異常な文字を含む名前のファイルを処理する必要があります。
nullglob_shopt=$(shopt -p nullglob)
後で使用して、以前の状態に$nullglob
戻すことができますnullglob
。
$()
特にCygwinでは、コマンドがビルトインのみを使用している場合でも、コマンド置換(またはバックティック)の使用は避けるのが一般的です。また、コマンドが実行されるサブシェルコンテキストにより、コマンドが予期しない動作をする場合があります。また、コマンドを変数(などnullglob_shopt
)に格納しないようにしています。これは、変数の値を誤って取得すると、非常に悪い事態が発生する可能性があるためです。
cat
!」の方法が複数あることは確かです。これにより多くの作業が必要な場合でも、人々の概念を示す利点があります。+1してください!
異常なファイル名(有効な\n
文字を含むファイルなど)は、この種の解析で大混乱を引き起こす可能性があります。Perlでこれを行う方法を次に示します。
perl -le '@sorted = map {$_->[0]}
sort {$a->[1] <=> $b->[1]}
map {[$_, -M $_]}
@ARGV;
print $sorted[0]
' b2*
それはそこで使用されるシュワルツ変換です。
stat
ファイルグロブとファイルの時間を先頭に追加して、decorate-sort-undecorateを使用できます。
$ stat -f "%m%t%N" b2* | sort -rn | head -1 | cut -f2-
stat
オプションを正しく覚えていれば、これはMac / FreeBSDバージョンのの可能性があります。他のプラットフォームで同様の出力を取得するには、次のように使用できますstat -c $'%Y\t%n' b2* | sort -rn | head -n1 | cut -f2-
find ... xargs ... head ...
上記の解決策が必要な人のためのダークマジック関数の呪文ですが、関数形式が使いやすいので、考える必要はありません。
#define the function
find_newest_file_matching_pattern_under_directory(){
echo $(find $1 -name $2 -print0 | xargs -0 ls -1 -t | head -1)
}
#setup:
#mkdir /tmp/files_to_move
#cd /tmp/files_to_move
#touch file1.txt
#touch file2.txt
#invoke the function:
newest_file=$( find_newest_file_matching_pattern_under_directory /tmp/files_to_move/ bc* )
echo $newest_file
プリント:
file2.txt
これは:
指定されたパターンに一致する指定されたディレクトリ下のファイルの最も古い変更されたタイムスタンプを持つファイル名。
findコマンドを使用します。
Bash 4.2以降を使用-printf '%T+ %p\n'
していると仮定して、ファイルのタイムスタンプ値に使用します。
find $DIR -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2
例:
find ~/Downloads -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2
より役立つスクリプトについては、https://github.com/l3x/helpersのfind-latestスクリプトをご覧ください。
これを達成するためのはるかに効率的な方法があります。次のコマンドを検討してください。
find . -cmin 1 -name "b2*"
このコマンドは、「b2 *」でワイルドカード検索を使用して、1分前に作成された最新のファイルを検索します。過去2日間のファイルが必要な場合は、以下のコマンドを使用することをお勧めします。
find . -mtime 2 -name "b2*"
「。」現在のディレクトリを表します。お役に立てれば。