

行いたい処理が2つあるのですがうまく書けずに困っています。  
処理したい事は下記になります。

### 1

  * フォルダAの中にある*.rarを再帰的に検索
  * 検索にヒットした*.rarファイルを全てzipファイル変換

[code]

    if [ *.rarをfindする処理 ]; then
        *.rarをzipに変換する処理
    fi
    
[/code]

### 2

  * フォルダBの中にあるファイル名に大文字の空白があるファイルを再帰的に検索
  * 検索にヒットしたファイルのファイル名の大文字の空白を削除する

[code]

    if [ 空白文字をfindする処理 ]; then
    　　sedで空白文字を削除処理
    fi
    
[/code]

何かいい書き方があれば教えていただければ幸いです。

例えば下記のようなディレクトリ構造です。

[code]

    animals  
    ├── bird  
    │   ├── bird_1.rar  
    │   ├── bird_2.rar  
    │   ├── bird_3.rar  
    │   ├── bird_4.rar
    │   ├── bird_5.rar
    │   └── penguin
    │       ├── p　enguin_1.txt
    │       ├── p　enguin_2.txt
    │       ├── p　enguin_3.txt
    │       ├── p　enguin_4.txt
    │       └── p　enguin_5.txt
    ├── cat
    │   ├── cat_1.rar
    │   ├── cat_2.rar
    │   ├── cat_3.rar
    │   ├── cat_4.rar
    │   └── cat_5.rar
    └── dog
        ├── dog_1.rar
        ├── dog_2.rar
        ├── dog_3.rar
        ├── dog_4.rar
        └── dog_5.rar
    
[/code]


CC BY-SA 3.0
2017-11-20T13:59:32.337
39713
2017-12-08T18:44:17.823
2017-11-23T17:17:49.807
3060
26264
question
bash shellscript
任意のフォルダの中を検索し、条件に一致したファイルがあれば処理をするシェルスクリプトを書きたい


こんなかんじではどうでしょう  
再帰的ではないですが、たぶん十分？

> 1  
>  ・フォルダAの中にある*.rarを再帰的に検索  
>  ・検索にヒットした*.rarファイルを全てzipファイル変換
[code]

    #!/bin/bash
    
    # 実行： ./rar2zip.sh [フォルダのパス]
    #
    # 以下のコマンドがいる
    # realpath, unrar, zip, mktemp
    
    function rar2zip {
        rar="$(realpath "$1")"
        zip="$(realpath "${2:-$(basename "$rar" .rar).zip}")"
        d=$(mktemp -d /tmp/rar2zip.XXXXXX)
        cd "$d"
        unrar x "$rar"
        zip -r "$zip" *
        mv -f $zip ${rar%/*}
        cd -
        rm -r "$d"
    }
    
    # 空白を含んだファイルを考慮に入れる場合以下のコメント外す
    # SAVEIFS=$IFS
    # IFS=$(echo -en "\n\b")
    
    FILES=$(find ${1} -name \*.rar -print)
    
    for rar in ${FILES[@]}
    do
        rar2zip "${rar}"
    done
    # IFS=$SAVEIFS
    
[/code]

**EDIT** : @nekketsuuu さんにコメントで指摘されている空白文字の対応

findとxargsで処理を書いていたのですが、これだとfindコマンドで見つけたファイルパスに空白が混じるとうまくいかないようです。

以下のサイトに関連する情報があります

  * [find と xargs の組み合わせ 【2017-06-10 -exec {} + を追加】](http://x68000.q-e-d.net/~68user/unix/pickup?find#prgmemo-find-xargs)

ご指摘の通り `find ... -exec +` で実行するか `find ... -print0`
でパスを取得するのがよさそうです。Emacsでgrep-findすると、`-print0` で出るのはそのためなんですねえ。

しかも、ファイルに空白が含まれているとファイルパスをシェルの配列に詰めるときファイルパスが空白で分割されて格納されてしまう…これは確かにfindから-
execで実行したほうがよさそう…

> 2  
>  ・フォルダBの中にあるファイル名に大文字の空白があるファイルを再帰的に検索  
>  ・検索にヒットしたファイルのファイル名の大文字の空白を削除する

[Remove whitespaces from filenames in Linux
[closed]](https://stackoverflow.com/questions/15347843/remove-whitespaces-
from-filenames-in-linux)

[code]

    #!/bin/bash
    
    BLANK_FILES=$(find ${1} -type f -print | grep '[[:blank:]]')
    
    for blank in ${BLANK_FILES[@]}
    do
        #echo $blank
        mv "$blank" "${blank//[[:blank:]]}"
    done
    
[/code]

**EDIT** : コメントで提供してもらったものを追記

ワンライナー版

[code]

    find . -type f -name "*[[:blank:]]*" -exec bash -c 'mv "$1" "${1//[[:blank:]]}"' _ {} \;
    
[/code]


CC BY-SA 3.0
2017-11-20T14:32:16.647
39714
2017-11-27T02:25:45.763
2017-11-27T02:25:45.763
4715
4715
39713
answer


仕事か授業の課題の丸投げですか? ヒントのみ。

指定したディレクトリ下のすべての `*.rar` ファイルを表示するだけ。`echo "$rar"` の部分を RAR → ZIP
するシェルスクリプトを組めば 1 の課題は完成。

[code]

    #!/bin/sh
    find "$@" \
      -type f \
      -name '*.rar' \
      -exec sh -c \
        'for rar in "$@"; do echo "$rar"; done' \
        sh {} + \
    ;
    
[/code]

同様に 2 も簡単ですね。

`find` の `-exec`
節のシングルクォート内にシェルスクリプトを記述するのが気持ち悪いとかなら、ちょっと遅いけどこんな風にも書けます。指定したディレクトリ下の名前にいわゆる全角スペース
(U+3000 IDEOGRAPHIC SPACE)
を含むファイルの名前を列挙するだけの例。ただし、ファイル名に改行を含むものが存在する場合はうまく動きません。

[code]

    #!/bin/sh
    find "$@" \
      -type f \
      -name '*　*' \
      -print \
    |while IFS= read -r name; do
      echo "$name"
    done
    
[/code]


CC BY-SA 3.0
2017-11-22T03:16:32.727
39753
2017-11-23T05:28:40.443
2017-11-23T05:28:40.443
3061
3061
39713
answer


その後、皆さんから頂いた情報なども吟味して自分で下記のワンライナーのソースを  
考えたのですが何か問題がありますでしょうか？

> 2  
>  ・フォルダBの中にあるファイル名に大文字の空白があるファイルを再帰的に検索  
>  ・検索にヒットしたファイルのファイル名の大文字の空白を削除する
[code]

    find . -name "*　*" -print0| xargs -0 rename s/　/" "/
    
[/code]


CC BY-SA 3.0
2017-12-08T17:26:23.217
40141
2017-12-08T18:44:17.823
2017-12-08T18:44:17.823
26264
26264
39713
answer