忘れそうなコマンドの備忘録

# 動画の情報を取得
### 1つの動画の長さを取得

```bash
ffprobe [動画ファイルのパス] -show_entries stream=duration -v error -hide_banner -of csv=p=0:s=, -select_streams v
```
`stream`を`width`,`height`,`r_frame_rate`などと変更するとそれぞれ幅，高さ，fpsも取得可能．
`stream=width,height`のようにカンマで区切ることで同時に取得することも可能．

ちなみに`ffprobe`だけだと以下のように様々な情報が出力される．
![スクリーンショット 2022-02-10 221813 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284399/ae6c2c16-e611-9a63-e0fc-f63c9deec166.png)

ここから`grep`でDurationを切り取る場合は，

```bash
ffprobe [動画ファイルのパス] 2<&1 | grep Duration
```
として標準エラー出力を標準出力に変更しなければならないことに注意．



### カレントディレクトリ以下の全ての動画の長さを取得

```bash
find ./ -name "*.mp4"  -exec ffprobe {} -show_entries stream=duration -v error -hide_banner -of csv=p=0:s=, -select_streams v \; 
```



# HMDB51の訓練用と検証用のデータ数の計測
### 訓練用と検証用のスプリットがいくつか存在する場合
HMDB51のようにラベルごとにスピリット情報が書かれたファイルがある場合，つまりラベル「brush_hair」の第1スピリットの情報がbrush_hair_test_split1.txtに書かれているような場合を考える．

![スクリーンショット 2022-02-11 013525 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284399/1a215fb5-4be4-3ada-dd5c-64747c1848dd.png)
上のようにファイルパス，スピリット番号（0が訓練でも検証でもないデータ，1が訓練データ，2が検証データ）となっている．
ラベルごとではなく全てのラベルで一括して動画数を取得したいので，以下のコマンドを使用する．

```bash
cat *_test_split1.txt |cut -d " " -f 2| sort |uniq -c
```
補足：`cut`でスピリット番号のみを切り取った後にソートし，`uniq -c`で重複をカウントする．

以下は出力結果．
![スクリーンショット 2022-02-11 014506 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284399/b0402413-b67c-7d27-df09-4d31c42f4ba7.png)



# テキストファイルを操作してラベル番号を変更
### ファイルパスとラベル番号が紐づいているファイルのラベル番号をラベル名の昇順に変更する
![スクリーンショット 2022-02-10 232153 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284399/87c54450-2220-4cc5-eb58-a685e26f862b.png)
上のようにファイルパス,ラベル番号でファイルのラベルが指定されているテキストファイルがある場合（注：実際のファイルを5000行おきに出力したファイル）について考える．今のままではラベル番号がラベル名の昇順になっていないので昇順にする．
ファイルがラベルごとにラベル名のディレクトリに分かれていることを利用する．

方針

- ラベル（ディレクトリ）名でソートする
- ラベル番号を0から付けて，ラベル（ディレクトリ）名が変わったら+1する

使用したコマンドは以下

```bash
cat labeled_file_path.txt |sort|awk -F "/" 'BEGIN{name=" "} BEGIN{id=-1} {if(name==$2){id+=0}else{id+=1}} {print "/" $2 "/" $3 "," id} {name=$2}'|cut -f 1,3 -d ","
```

補足：`awk`を使って1行毎にラベル名を保持する（コマンドでは`name=$2`に相当）．
1行毎にラベル名（コマンドでは`$2`に相当）と`name`（この時点で1行前のラベル名となる）が一致しているかを確認し，一致していない場合のみラベル番号（コマンドでは`id`に相当）を+1する．ラベル名を保持するために`awk`の区切り文字は`/`にしたため，このままでは元のラベル番号まで出力されてしまうため`cut`で区切る．

以下は実際の出力
![スクリーンショット 2022-02-11 000510 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284399/7b5f9c98-1bca-6f03-5c57-e9d4bae18d96.png)

追記：
`awk`の区切り文字は複数指定できるので，以下のコマンドの方が簡潔．

```bash
 cat labeled_file_path.txt |sort|awk -F "[/,]" 'BEGIN{name=" "} BEGIN{id=-1} {if(name==$2){id+=0}else{id+=1}} {print "/" $2 "/" $3 "," id} {name=$2}'
```

# サーバ間でデータを移動
### 大量のファイル移動はrsyncを使う
`rsync`を使う理由

- 変更分を検出して差分のみを転送してくれる
    - 転送処理が途中で中断されても途中から再開できる
- サーバ間でデータの転送が行える

以下はコマンド

```bash
rsync -av [コピー元] [コピー先]
``` 
オプションについて
a: 元のパーミッションを保持
v: 処理中の経過ファイル名の表示

注意点はコピー元のディレクトリのパスの最後に`/`を付けてしまうと，指定したディレクトリ以下のディレクトリがコピー先のディレクトリ以下に転送され，コピー元で指定したディレクトリ自体が保存されない．（Tab保管を使うと`/`まで入ってしまうのでやりがちなミス）

# 参考

- [awkコマンドの基本](https://qiita.com/yamazon/items/563af1b485ff413d381f#%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E5%8C%BA%E5%88%87%E3%82%8A%E6%96%87%E5%AD%97%E3%81%AF%E8%A4%87%E6%95%B0%E6%8C%87%E5%AE%9A%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99)
- [はじめてrsyncを使う方が知っておきたい6つのルール](https://www.itmedia.co.jp/enterprise/articles/0804/21/news013.html)