shell) 連番のテキストファイルの内容を連結

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
moba
記事: 82
登録日時: 8年前

shell) 連番のテキストファイルの内容を連結

#1

投稿記事 by moba » 5年前

shell) 連番テキストファイルの内容を連結するワンライナ


 こんばんは! お世話になります。
 シェル初心者です。シェルの使い方について、質問させてください。環境はbash (OS X) です。


 複数のテキストファイルの内容を、改行3つで区切って、連結したいです。
 たとえば、ディレクトリ下のファイルが……


ファイル名 テキストの内容

a.txt    "ああああ"
b.txt    "いいいい"


 となっていた場合、"ああああ\n\n\nいいいい" という出力が欲しいです。
 "ああああ\n\n\nいいいい\n\n\n"でも妥協できます。


 今回は特に、ファイル名が連番で始まるテキストファイルの内容を、改行3つで区切って連結したいです。(ファイル名の例: 0 aaa AAA.txt, 1 bbb BBB.txt など)
オフトピック
 理想的には、以下のように書きたいです。

コード:

join separator (map cat files) > merged.txt
 bashでは、コマンドが文字列を返せない? などの問題で、無理なのかと思います。
 このように、コンパクトな書き方ができるシェルは無いのでしょうか……?(趣味なので、ガラパゴスでも構いません)
 bashで連結する方法を考えます。
 簡単のため、次のコマンド・オプションは使いたくありません:

・while
・find -exec

 以下のように、bashで書いてみました。見よう見まねです。

コード:

# ヌル文字区切りでファイルを集める
$ find *.txt -print0 | sort -z -n # 番号順にソートできていることを確認
0.txt1.txt .. 11.txt12.txt ..
$ find *.txt -print0 | sort -z -n | xargs -0 -I{} echo -e $(cat "${}") "\n\n\n"
-bash: ${}: bad substitution
 できればxargsで動作させたいのですが、何とか成功させられないでしょうか。
 よろしくお願いします。

[追記] 誤字を修正しました

かずま

Re: shell) 連番のテキストファイルの内容を連結

#2

投稿記事 by かずま » 5年前

moba さんが書きました:
5年前
 となっていた場合、"ああああ\n\n\nいいいい" という出力が欲しいです。
 "ああああ\n\n\nいいいい\n\n\n"でも妥協できます。
これではだめですか?

コード:

$ cat a.txt
ああああ
$ cat b.txt
いいいい
$ for f in *.txt;do cat $f;printf "\n\n\n";done
ああああ



いいいい



$

かずま

Re: shell) 連番のテキストファイルの内容を連結

#3

投稿記事 by かずま » 5年前

これは?

コード:

$ s="";for f in *.txt;do printf "$s";cat $f;s="\n\n\n";done
ああああ



いいいい
$

かずま

Re: shell) 連番のテキストファイルの内容を連結

#4

投稿記事 by かずま » 5年前

9.txt と 10.txt があった場合、9.txt を先にしないといけないんですね。

コード:

$ s="";for f in $(ls *.txt|sort -n);do printf "$s";cat $f;s="\n\n\n";done

かずま

Re: shell) 連番のテキストファイルの内容を連結

#5

投稿記事 by かずま » 5年前

ls *.txt | sort -n は、ls -v *.txt でもよいようです。

ファイル名にスペースが入っているんでしょうか?

コード:

$ :>s;ls -v *.txt|xargs -d'\n' -n1 -I{} sh -c 'cat s "{}";printf "\n\n\n">s'

moba
記事: 82
登録日時: 8年前

Re: shell) 連番のテキストファイルの内容を連結

#6

投稿記事 by moba » 5年前

> かずま さん
質問文の読み込みと、返信をありがとうございます!

> ファイル名にスペースが入っているんでしょうか?
はい、入っています。

> for f in $(<command>); do ..
盲点でした。ありがとうございます。

> for の do 中の cat $f
読み込みに失敗するファイルがあり、cat "$f" だと読んでくれました。

> xargs -d '\n'
xargs: illegal option -- d と出ました。
GNU専用でMacには無いオプション、と、どこかで読んだ気がします。

現環境(Mac)では、改行ではなくヌル文字区切りで行こうと思います。

> xargs -I{} sh -c 'cat "{}" .. '
動いてくれました。ありがとうございます!
以下は、変数sを作らずに、xargsはヌル文字区切りを使うバージョンです。

コード:

find *.txt -print0 | sort -z -n | xargs -0 -I{} sh -c 'cat "{}"; printf "\n\n\n"' > ../merged.txt
質問文で使用した$(<command>)ですが、コマンド置換と呼ぶそうですね。
質問文のエラーは、変数{}のスコープが切れていたような印象です。

エラーの理由は分かりませんが、替わりが見つかって良かったです。
解決済みとします。ありがとうございました!

---
手続き的なやり方を考えてみました。

コード:

find *.txt | sort -n | while read f; do cat "$f"; printf '\n\n\n'; done > ../merged.txt
xargsを使ったバージョンよりも、読みやすいです……。

関数型の書き方が分かりやすいと信じ、
近い書き方がしたくて質問しましたが、
bashの場合、手続き的に書く方が素直なのかもしれませんね……。

質問前よりも、bashに合わせる気持ちが湧いて来ました。

返信

“C言語何でも質問掲示板” へ戻る