7

テキスト ファイルのディレクトリをループして、それらを 1 つのドキュメントに結合しようとしています。これはうまく機能しますが、テキスト ファイルにはコード スニペットが含まれており、すべての書式設定が左側に折りたたまれています。行の先頭の空白はすべて取り除かれます。

#!/bin/sh
OUTPUT="../best_practices.textile"
FILES="../best-practices/*.textile"
for f in "$FILES"
do
  echo "Processing $f file..."
  echo "">$OUTPUT

  cat $f | while read line; do 
      echo "$line">>$OUTPUT
  done
  echo >>$OUTPUT
  echo >>$OUTPUT
done

私は確かにbash初心者ですが、高低を検索した後、適切な解決策を見つけることができませんでした. どうやら BASH は一般的に先頭の空白を嫌うようです。

4

5 に答える 5

40

他の人が指摘しているように、read-echoループの代わりにcatまたはawkを使用することは、これを行うためのはるかに優れた方法です-空白のトリミングの問題(およびあなたが遭遇していない他のいくつか)を回避し、より速く実行します、少なくとも猫の場合は、単純にクリーンなコードです。それでも、read-echoループを正しく機能させるために努力したいと思います。

まず、空白のトリミングの問題です。readコマンドは、先頭と末尾の空白を自動的にトリミングします。これは、IFS変数を空白に設定して空白の定義を変更することで修正できます。また、readは、行末の円記号が次の行が継続であることを意味し、これと一緒に接続する必要があることを前提としています。これを修正するには、-r(raw)フラグを使用します。ここでの3番目の問題は、echoの多くの実装が文字列内のエスケープシーケンスを解釈することです(たとえば、\ nが実際の改行に変わる可能性があります)。これを修正するには、代わりにprintfを使用してください。最後に、一般的なスクリプトの衛生規則と同様に、実際に必要がない場合はcatを使用しないでください。代わりに入力リダイレクトを使用してください。これらの変更により、内部ループは次のようになります。

while IFS='' read -r line; do 
  printf "%s\n" "$line">>$OUTPUT
done <$f

...周囲のスクリプトには他にもいくつかの問題があります。使用可能な.textileファイルのリストとしてFILESを定義しようとする行には引用符が付いています。つまり、実際のファイルのリストに展開されることはありません。これを行う最良の方法は、配列を使用することです。

FILES=(../best-practices/*.textile)
...
for f in "${FILES[@]}"

(ファイル名のいずれかにスペースやその他の面白い文字が含まれている場合は、$ fのすべての出現箇所を二重引用符で囲む必要があります。ただし、スクリプトで定義されているため、実際には安全です。やめる。)

最後にecho "">$OUTPUT、ループオーバーファイルの上部近くに、毎回出力ファイルを消去します(つまり、最後に、最後の.textileファイルのみが含まれます)。これはループの前に移動する必要があります。ここでの目的がファイルの先頭に1行の空白行を配置することなのか、ファイル間に3行の空白行(および最初に1行、最後に2行)を配置することなのかわからないため、正確にはわかりません。適切な交換はです。とにかく、これらの問題をすべて修正した後、私ができることは次のとおりです。

#!/bin/sh
OUTPUT="../best_practices.textile"
FILES=(../best-practices/*.textile)

: >"$OUTPUT"
for f in "${FILES[@]}"
do
  echo "Processing $f file..."
  echo >>"$OUTPUT"

  while IFS='' read -r line; do 
    printf "%s\n" "$line">>"$OUTPUT"
  done <"$f"

  echo >>"$OUTPUT"
  echo >>"$OUTPUT"
done
于 2009-10-30T22:45:10.713 に答える
4

これは、ファイルを結合する非常に高価な方法です。

cat ../best-practices/*.textile >  ../best_practices.textile

連結時に各ファイルに空白 (改行) を追加する場合は、awk を使用します。

awk 'FNR==1{print "">"out.txt"}{print > "out.txt" }' *.textile

また

awk 'FNR==1{print ""}{print}' file* > out.txt
于 2009-10-30T05:28:20.723 に答える
4

それ以外の:

cat $f | while read line; do 
    echo "$line">>$OUTPUT
done

これを行う:

cat $f >>$OUTPUT

(行ごとに行う必要がある理由がある場合は、それを質問に含めることをお勧めします。)

于 2009-10-30T04:54:37.343 に答える
1

これにより、元のスクリプトで行ったように、各入力ファイル間に改行を挿入できます。

for f in $FILES; do echo -ne '\n\n' | cat "$f" -; done > $OUTPUT

これが機能するためには引用符で囲まれていないことに注意してください$FILES(そうでない場合、余分な改行はすべての出力の最後に1回だけ表示されます)が$f、ファイル名のスペースが存在する場合は保護するために引用符で囲む必要があります。

于 2009-10-30T06:16:39.067 に答える
0

正解は、以下に再現された thisです。

while IFS= read line; do
    check=${line:0:1}
done < file.txt

入力が実際のファイルからだけでなく、別のコマンドからパイプされる状況を処理することに注意してください。

以下に示すように、リダイレクトを単純化することもできます。

#!/bin/bash
OUTPUT="../best_practices.textile"
FILES="../best-practices/*.textile"
for f in "$FILES"
do
  echo "Processing $f file..."
  {
  echo

  while IFS= read line; do 
      echo "$line"
  done < $f
  echo
  echo;
  } > $OUTPUT
done
于 2015-12-09T19:42:12.833 に答える