
[code]

    $ ls
    hoge.text fuga.text piyo.text all.text
    $ cat hoge.text
    hoge
    $ cat fuga.text
    fuga
    $ cat piyo.text
    piyo
    $ cat all.text
    hoge
    fuga
    piyo
    $ echo hoge >> hoge.text
    $ cat all.text
    hoge
    hoge
    fuga
    piyo
    
[/code]

こういうことって可能ですか？


CC BY-SA 3.0
2015-09-16T09:59:59.363
16689
2015-09-23T07:02:27.413
10439
question
linux bash
複数のファイルを1つのファイルのように参照する方法


ええ、まぁ、できなくはないですよ。ただ、以下に説明する方法で納得していただけるどうかは、、分かりませんが。

Linux OS にはファイルシステムで発生するイベントを選択的に感知するための API が提供されています。`inotify`
と呼ばれていますが、これを使ってみます。

まずは inotify 関連のパッケージをインストールします。Ubuntu Linux の場合は `inotify-tools` がそれに当たります。

[code]

    $ sudo apt-get install inotify-tools
    
[/code]

それでは例として、`$HOME/tmp` に対象のファイルが置いてあるとします。

[code]

    $ cd $HOME/tmp
    $ ls
    fuga.text  hoge.text  piyo.text
    
[/code]

次に以下のシェルスクリプトを実行します。

**update.sh**

[code]

    #!/bin/bash
    
    target_dir=$HOME/tmp
    files=(fuga.text hoge.text piyo.text)
    all=all.text
    
    while inotifywait -qq -e modify @"$all" "$target_dir";
    do
      (cd "$target_dir" && cat "${files[@]}" > "$all")
    done
    
[/code]

[code]

    $ ./update.sh &
    
[/code]

では実際にファイルを変更してみます。

[code]

    $ cd $HOME/tmp
    $ echo hoge >> hoge.text
    $ cat all.text
    fuga
    hoge
    hoge
    piyo
    
[/code]

スクリプト内の `inotifywait` コマンドは `$HOME/tmp`
ディレクトリ内のファイルが変更されるのを待ちます。ただし、`$HOME/tmp/all.text` を除いて、です(`@"$all"`)。

`$HOME/tmp` ディレクトリ内には上記のファイルのみが存在することが条件です。他にファイルがある場合には `inotifywait`
コマンドに対象ファイルのみを指定することになりますが、具体的な指定方法は `inotifywait(1)` を参照して下さい。


CC BY-SA 3.0
2015-09-16T11:09:41.757
16690
2015-09-16T11:09:41.757
16689
answer


質問の例ですとファイルを使っているのは`cat`コマンドのみですね。  
この様に、一度に一つのプロセスがファイル先頭から順に最後まで読む、という前提でしたら別のプロセスの出力を読ませる事で実現できます。  
（前提なしで、きちんと通常のファイルとして振る舞わせるには fuse
などで複数ファイルをバックエンドにしたファイルを作れるファイルシステムを作るしか無いと思います）

### 名前付きパイプを使う方法

まず、名前付きパイプのファイルを作ります。

[code]

    mkfifo all.txt
    
[/code]

そして、ファイルを連結して出力するプロセスをバックグラウンドで起動します。今回は`cat`を使う事にします。

[code]

    cat hoge.txt fuga.txt piyo.txt >all.txt &
    
[/code]

この状態で all.txt を読むと、上記の出力用のプロセスから受けとる事になります。  
（まぎらわしいので、読む側のコマンドには **以後`nl` を使います**）

[code]

    nl all.txt
    #以下出力
         1  hoge
         2  fuga
         3  piyo
    
[/code]

最後まで読むと、出力用のプロセスは終了しますから、もう一度読もうとすると all.txt への入力を待機した状態でストップする事になります。  
例えば下記の様に、出力用のプロセスを繰り返し実行するようにすると、何度でも読めることになります。

[code]

    while true; do cat hoge.txt fuga.txt piyo.txt >all.txt; done &
    
[/code]

### Bash のプロセス置換を使う方法

Bash には名前付きパイプを使う方法と同じ様な事を、自動でやってくれる機能があります。  
ただ、この方法ではファイル名は指定できないので、all.txt でなければならない場合は使えません。

Bash のコマンド行では `<(コマンド)` という表記はファイル名に置き換えられます。

[code]

    ls <(echo hello)
    # 手元の環境での出力: /dev/fd/63
    # ファイル・ディスクリプターを使っている様です
    # 環境によっては名前付きパイプを使うらしいです
    
[/code]

このファイルは bash が用意した物で、コマンド行で実行されたメインのプロセス（上記の例ですと`ls`）が読む場合のみ有効です。  
`<()` の中で指定されたコマンドの出力がつなげられています。  
質問の例ですと下記の様に実行すればよいです。

[code]

    nl <(cat hoge.txt fuga.txt piyo.txt)
    # 以下出力
         1  hoge
         2  fuga
         3  piyo
    
[/code]


CC BY-SA 3.0
2015-09-23T06:43:56.090
16871
2015-09-23T07:02:27.413
2015-09-23T07:02:27.413
3054
3054
16689
answer