web-dev-qa-db-ja.com

ファイルのリストに基づいてファイルの場所と内容を出力します

locationfile.txtと呼ばれるさまざまなファイルの場所を含むファイルがあります。

/home/user/documents/file1
/home/user/file2
/home/user/file3

各テキストファイルには約10行あり、すべてのファイルをfinalfileという別のファイルに出力したいと思います。

私がそうするなら私はそれを理解しました

cat locationfile.txt | while read line; do cat "$line"; done

これにより、すべてのファイルが一緒に印刷されるため、最大30行のテキストファイルになります。

私の質問は、次のように、テキストの間にファイルの場所を含めて、そのファイルを出力する方法を教えてください。

/home/user/documents/file1
text
text
text
""
/home/user/file2
text
text
text
""
/home/user/file3
text
text
text
""
5
user211145

catの前に、ファイル名のechoまたはprintfを実行します。

while read line; do printf '%s\n' "$line"; cat "$line"; done <locationfile.txt >finalfile

または、より読みやすく:

while read line; do
  printf '%s\n' "$line"
  cat "$line"
done <locationfile.txt >finalfile

これには、locationfile.txt内のすべてのパスに\が含まれていない必要があることに注意してください。

パス名に\を含めることは非常に珍しいことですが、より安全です。

while read -r line; do
  printf '%s\n' "$line"
  cat "$line"
done <locationfile.txt >finalfile

...同じ制限はありません。

ファイルも実際に存在することを確認するためのチェックを追加し、存在しない場合は警告を出力します。

while read -r line; do
  if [[ -f "$line" ]]; then
    printf '%s\n' "$line"
    cat "$line"
  else
    printf 'Warning: "%s" does not exist\n' "$line" >&2
  fi
done <locationfile.txt >finalfile

ここでの「存在しない」とは、「少なくとも通常のファイルではない」という意味です。

そこにも""が必要な場合は、一種のファイルの終わり-コンテンツ-マーカーとして、catの後にそれを入れてください。

while read -r line; do
  if [[ -f "$line" ]]; then
    printf '%s\n' "$line"
    cat "$line"
    echo '""'
  else
    printf 'Warning: "%s" does not exist\n' "$line" >&2
  fi
done <locationfile.txt >finalfile

そして最後に、自己文書化の名前を付けます。

while read -r file_path; do
  if [[ -f "$file_path" ]]; then
    printf '%s\n' "$file_path"
    cat "$file_path"
    echo '""'
  else
    printf 'Warning: "%s" does not exist\n' "$file_path" >&2
  fi
done <file_paths.txt >files_concat_with_paths.txt
8
Kusalananda
while read file; do
    ( echo "$file"; cat "$file"; echo '"""' ) >> /path/to/outputfile
done < /path/to/filelist
3
DopeGhoti

GNU awkがある場合、シェルループを完全に回避するオプションは次のとおりです。

xargs -d '\n' -a locationfile.txt gawk 'BEGINFILE{print FILENAME} 1' > newfile

またはGNU sed:

xargs -d '\n' -a locationfile.txt sed -s '1F' > newfile

ファイル名の正確な形式を気にしない場合は、このトリックをheadで使用できます。

xargs -d '\n' -a locationfile.txt head -vn -0 > newfile

-n -0headに、最初の0を除くすべての行(つまり、すべての行)を出力するように指示します。

3
steeldriver

別のPerlアプローチ:

$ Perl -le 'do{print $_,`cat $_`,"\"\"";} for <>' locationfile.txt
text
text
text
""
text
text
text
""
text
text
text
""

これはPerlの魔法を少し使っているので、説明が必要かもしれません。 -lは、各入力行から末尾の改行を削除し、各print呼び出しに改行を追加します。 -eは、スクリプトをPerlに与える方法です。

さて、<>は「配列に分割された入力ファイルの内容」です。したがって、do {foo} for <>は入力ファイルの各行でfooを実行します。そのforループ内で、特別な変数$_が各入力行に割り当てられます。 `command`構文は、デフォルトのシェル(システムコール)でcommandを実行し、その出力を返します。したがって、cat $_locationfile.txt内の各ファイル名をcatします。

全体として、print $_,`cat $_`,"\"\""はファイル名(現在は$_にあります)、cat(ファイルの内容)の結果、次に""を出力します(ただし、エスケープする必要があります)それらなので、\"\")。

言い換えると、そのスクリプトは、「各入力行を読み取り、それを印刷し、そこに含まれるファイルをcatし、各ファイルの後に""を印刷することを意味します。

3
terdon

ループにecho "$line"を追加するだけです。

cat locationfile.txt | while read line; do echo "$line" && cat "$line"; done
2
pbm

system()関数を介したAWKアプローチ。 sprintfを介してコマンド文字列を作成し、それをsystem()に渡します。

$ awk '{print $0; cmd=sprintf("cat \"%s\"",$0);system(cmd); print "\"\""}' filenames.txt                                 
/home/xieerqi/input1.txt
Hello, I am input file #1
And this is second line of the text
""
/home/xieerqi/input2.txt
And I am input file #2
Roses are red, violets are blue
AWK is awesome, Python is too
""
/etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 127.0.1.1
""

そしてPerlのアプローチですが、コード内でファイルを開くことで:

$ Perl -ne 'chomp; open($fh,$_) or die;print "$_\n";while($line = <$fh>){ print $line; print "\"\"\n" if eof}' filenames>
/home/xieerqi/input1.txt
Hello, I am input file #1
And this is second line of the text
""
/home/xieerqi/input2.txt
And I am input file #2
Roses are red, violets are blue
AWK is awesome, Python is too
""
/etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 127.0.1.1
""
2