質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

Q&A

解決済

3回答

3700閲覧

ファイル名の末尾の日付から最も古い日付のファイルを取得する方法を教えてください。

koichi8888

総合スコア24

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

0グッド

0クリップ

投稿2018/12/20 12:30

編集2018/12/20 14:21

前提・実現したいこと

CSVファイルをソースフォルダから格納先に移動し、格納先で削除するという処理をシェルで実装したいです。
具体的には末尾の日付のみが違うファイルがある場合にタイムスタンプが古いファイルか格納先に移動し、格納先フォルダのファイルをすべて削除した後、ソースフォルダに残っているタイムスタンプが新しいファイルを移動し、削除というループ処理をしたいです。
※日付のみ違うファイルは3つ以上あることを想定しています。

日付が最も古いファイルを移動する処理の実装でファイルから日付部分を取得する方法はわかるのですが、下記の実装方法を教えてください。
・最も日付が古いファイルを取得する
⇒取得したファイル名($f)を配列に格納し、日付部分を比較し、最も古いファイルをmvで移動する

また、IF文やループをたくさん記述しないといけないので、他の効率的なコードの書き方がないかを教えてほしいです。

/src/csv
FILE_A_yyyymmddhhmmss
FILE_A_yyyymmddhhmmss
FILE_A_yyyymmddhhmmss
FILE_B_yyyymmddhhmmss
FILE_B_yyyymmddhhmmss

該当のソースコード

bash

1 2############### ローカル変数定義 ############### 3# ディレクトリ 4CSV_SRC_DIR="/src/csv" # ソースディレクトリ 5CSV_DST_DIR="/dst/csv" # 格納先ディレクトリ 6 7# 検索キー 8KEY_A=FILE_A 9KEY_B=FILE_B 10 11# カウント初期化 12KEY_A_count=0 13KEY_B_count=0 14 15############### メイン処理 ############### 16while <フォルダが空になるまで>; do 17 18 #ディレクトリ移動 19 cd $CSV_SRC_DIR 20 21 # ファイル名取得 22 array=($(ls -1tr /src/csv)) 23 24#ファイル名別の数をカウント 25 for f in ${array[@]}; do 26 27 if [[ $f == "$KEY_A"* ]]; then 28 KEY_A_count=`expr $KEY_A + 1` 29 30 elif [[ $f == "$KEY_B"* ]]; then 31 KEY_B_count=`expr $KEY_B + 1` 32 done 33 34# ファイル移動 35 for f in ${array[@]}; do 36 if [[ $f == "$KEY_A"* ]]; then 37 if [ $KEY_A_count -eq 1 ]; then 38 mv $f $DST_DIR/RENAME_A.csv 39 40 # 日付のみ違うファイル名が複数ある場合、タイムスタンプが古いファイルから格納フォルダに移動 41 elif [ $KEY_A_count -gt 1 ]; then 42 # 日付が最も古いファイルを移動 43 if [[ $f == "$KEY_A"* ]]; then 44 array=("${array[@]}" "$f") 45 DATE=`echo ${f##*_} | sed 's/.[^.]*$//'` 46 fi 47     else 48 : 49 fi 50fi 51 52 if [[ $f == "$KEY_B"* ]]; then 53 if [ $KEY_B_count -eq 1 ]; then 54 mv $f $DST_DIR/RENAME_B.csv 55 56 # 日付のみ違うファイル名が複数ある場合、タイムスタンプが古いファイルから格納フォルダに移動 57 elif [ $KEY_B_count -gt 1 ]; then 58 # 日付が最も古いファイルを移動 59 if [[ $f == "$KEY_B"* ]]; then 60 array=("${array[@]}" "$f") 61 DATE=`echo ${f##*_} | sed 's/.[^.]*$//'` 62 fi 63 else 64 : 65 fi 66 fi 67 68 69 done 70 71rm -f $CSV_DST_DIR 72done

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2018/12/20 13:34

タイトルが「タイムスタンプが最も古い」で、質問文中が「取得したファイル名($f)を配列に格納し、日付部分を比較し、」と矛盾してますが、もし本文が正しく、チェックするのはファイル名であり、タイムスタンプは関係ないということであれば、タイトルを変更しましょう。
koichi8888

2018/12/20 14:24

ご指摘ありがとうございます。タイトルを変更させて頂きました。実装したいことはファイル名の日付から判断したいです。
koichi8888

2018/12/20 14:26 編集

タイムスタンプの場合でも同様ですが、$fを配列に格納し、比較する必要があると思うのですが、その実装方法が知りたいです。
guest

回答3

0

sh

1ls -tr | head -1

投稿2018/12/20 12:38

yambejp

総合スコア114839

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

koichi8888

2018/12/21 03:07

ご回答ありがとうございます。headという便利コマンドがあるんですね!
yambejp

2018/12/21 03:09

ごめんなさい、ファイル名から処理するんでしたね 私のはあくまでファイルの更新日の古い方からとる処理でした
guest

0

質問の意味が「ファイル名の日付以外が同じファイルのうち、日付が最新のもの以外を移動する」ということでしたら、こんな感じでしょうか。

sh

1cd $CSV_SRC_DIR 2mv $(ls | sed -e 's/(.*)_(.*)/\1 \2/' | sort -r -k1,2 | awk '{ if(p==$1){ printf "%s_%s\n", $1, $2 }; p=$1 }') $CSV_DST_DIR

投稿2018/12/21 02:12

emasaka

総合スコア524

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

・最も日付が古いファイルを取得する

⇒取得したファイル名($f)を配列に格納し、日付部分を比較し、最も古いファイルをmvで移動する

array=($(ls -1 /src/csv))でファイル名をセットすれば、arrayにはファイル名が辞書順に格納されるので、ファイル名の先頭部分が同じFILE_A_でその後が日時なら、最初に出てくるものが一番古い事になります。

2番目以降のファイルをどうしたいのか分からないけど、こんな感じで。

Bash

1CSV_SRC_DIR=/src/csv 2CSV_DST_DIR=/dst/csv 3 4DoIt(){ 5 key=$1 6 new=$2 7 cd $CSV_SRC_DIR 8 array=($(ls -1 $key*)) 9 count=${#array[@]} 10 if [ $count -gt 0 ] 11 then 12 mv ${array[0]} $DST_DIR/$new 13 unset array[0] 14 for f in ${array[@]} 15 do 16 2つ目以降の処理(1つしか無ければこのループは回らない) 17 done 18 fi 19} 20 21 22DoIt FILE_A RENAME_A.csv 23DoIt FILE_B RENAME_B.csv

投稿2018/12/21 01:10

otn

総合スコア84555

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

koichi8888

2018/12/21 05:41 編集

ご回答ありがとうございます。辞書順でソートすれば、日付の古い順になるんですね!下記のようにcountせず、古い日付のファイルを一つずつ移動し、whileでフォルダが空になるまでファイル移動⇒移動先で削除をループする処理にしました。 src_dir=/src dst_dir=/dst DoIt(){ key=$1 new=$2 cd ${src_dir} # 辞書順でソート f=($(ls -1 | grep "$key" | head -1)) if [ -n "$f" ]; then mv $f $dst_dir/$new #修正 fi } while [ -n "$(ls $src_dir)" ]; do DoIt FILE_A RENAME_A.csv #修正 DoIt FILE_B RENAME_B.csv #修正 rm -f $dst_dir done
otn

2018/12/21 05:33

↑なんんか変ですけど、大丈夫でしょうか?
koichi8888

2018/12/21 05:42

すみません、修正しました!
otn

2018/12/21 13:09

そこもですけど、最古のファイルを移動させて、whileループでまた次に古いファイルを移動させて、また次に古いファイルを移動させて、、、、、、と空になるまで処理すると結局最後に一番新しいファイルでmvで上書きすることになるのでは?
koichi8888

2018/12/22 15:58

ループを一回したら、rm -f $dst_dirで移動先のディレクトリの中身をすべて削除する処理なので、上書きすることはないと思っています。
otn

2018/12/22 16:11

移動先を消したら、移動する意味が無いのでは?
koichi8888

2018/12/22 16:37

説明不足ですみません、rmコマンドの部分は実際には別のスクリプトを呼び出して、そのスクリプトの最後にrmでディレクトリ配下のファイルが削除される処理になっております。説明で便宜上、rmコマンドとして記載しました。今回質問させて頂いた処理内容は意図した通りに動作しております。
otn

2018/12/22 16:46

ということは、そもそも、「一番古いファイルを移動したい」じゃなくて、 「ファイルを古い順に1つずつ順番に処理したい」が質問すべき事だったのでは?
koichi8888

2018/12/25 01:32

その通りですね。ループ処理という記述はしていたのですが、タイトルでそのように記述した方が良かったですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問