web-dev-qa-db-ja.com

forループ内のテキストファイルへの出力のパイピング

forループ内で次のことを実行しようとしています:

  • 条件を満たすファイルを見つける
  • ファイルの名前をログファイルにエコーします。
  • ファイルをgzipします。

スクリプトを使用してファイルを検索し、それらの名前を画面にエコーできますが、ファイルにパイプすることはできません。 (私はこれまでgzipの部分をテストしていません)

スクリプトの関連部分は次のとおりです($LOGCLEAN_FILEが存在し、スクリプトの前の部分に書き込まれます)。

for F in `find . -type f \( ! -name '*.gz' \) -a \( ! -name '*.Z' \) -mtime +7`
do

        {
        print "Will be compressing file  ${F}" >> $LOGCLEAN_FILE
        } ; 
        ##gzip $F
done

" >> $LOGCLEAN_FILE"テキストなしでスクリプトを実行すると、出力が画面に表示されます。

何が悪いのですか?

批判は大歓迎です-私はまだ学んでいます。

4
morgan_g

Findの出力を確実に後処理することはできません。使用する -exec in find

find . -type f ! -name '*.gz' ! -name '*.Z' -mtime +7 -exec sh -c '
  for i do
    printf "%s\n" "Will be compressing file $i"
    gzip "$i"
  done' sh {} + >> log

GNU findの実装)を使用すると、shを実行せずに回避することもできます。

find . -type f ! -name '*.gz' ! -name '*.Z' -mtime +7 \
  -printf 'Will be compressing file %p\n' -exec gzip {} + >> log
4

シェルループでfindの出力を再現する必要は本当にありません。 ファイル名のリストをパックする場合、一般的な式は次のとおりです。

find ... | gzip > logfile.gz

ファイル自体をgzipしたい場合は、次のように変更されます。

find ... | tar -czvf archive.tar.gz -T -

これはtarにファイルから作業するファイル名のリストを読み取るように指示し、単一の-は標準入力を表します。 (-T AKA --files-from=オプションはGNU tarにあります。他のフレーバーについてはわかりません。)もちろん、ファイルで作業するとどうなるでしょうか。名前に\nが含まれています。

4
peterph

リダイレクト(>>)をループの外(doneの後)に配置します。

for i in $(find . -type f \( ! -name '*.gz' \) -a \( ! -name '*.Z' \) -mtime +7);
  do echo "Will be compressing file  ${i}";
  ##gzip $i;
done >> $LOGCLEAN_FILE

または、最終的にgzipコマンドのコメントを外すことを計画している場合は、次のことを検討してください。

for i in $(find . -type f \( ! -name '*.gz' \) -a \( ! -name '*.Z' \) -mtime +7);
  do gzip "$i" && echo "Successfully compressed ${i}";
done >> $LOGCLEAN_FILE

&&は、前のコマンドが0(エラーなし)で終了した場合にのみ、次のコマンドを実行することを意味します。

2
h3rrmiller

ファイル名にはスペースと改行の両方を含めることができるため、考えられるアプローチは次のとおりです。

#!/bin/bash

logclean_file="logclean_file.txt"

ts="$(date)"

printf "%s\n" "$ts" > "$logclean_file"

# Set IFS blank
# -r Backslash does not act as an escape character. The  backslash
#    is  considered  to be part of the line.  In particular, a
#    back-slash-newline pair may not be used as a line continuation.
# -d delim
#    The  first  character  of  delim is used to terminate the input
#    line, rather than newline.
# 
# Here setting -d to nul or 0x00. This enables us to capture any file-
# names with the print0 from find.
#
# fn The variable to read into.
#
while IFS= read -r -d $'\x00' fn; do
    printf "Will perhaps be compressing file %s\n" "$fn" >> "$logclean_file"
    # If file + gz does not exist 
    if [[ ! -e "$fn.gz" ]]; then
            if gzip command "$fn"; then
                    echo "Horray! success!" >> "$logclean_file"
            else
                    echo "Harf! Gzip failed." >> "$logclean_file"
            fi
    else
            echo "Nah. Already exists." >> "$logclean_file"
    fi
done < <(find . -type f \( ! -name '*.gz' \) -a \( ! -name '*.Z' \) -print0)
# Notice -print0 at end which means find will print filenames, - separating
# them with 0x00 instead of new-line

移植性について:

echoprintも実際には移植可能ではありません。 printksh93に固有ですが、echoはPOSIXプロセスの非常に遅い時点で標準化されただけであり、古いバージョンを信頼して予測可能にすることはできません結果。 echo vs print および printfの方が優れている理由... を参照してください。

printf "Some %s\n" "$var" >> "$foo"
# Or
echo "Some $var" >> "$foo"

スタイルについて:

  • quote変数。
  • 小文字のユーザー変数(独自の変数)の使用を検討してください。

いくつかの参考文献:

TLDPガイドの場合、および stylish を使用している場合は、スクリーンリーディングのために one of these をお勧めします。

1
Runium

パイプで出力ファイルにアクセスしようとしている場合は、ファイルパスを繰り返し処理します...

Findのexec機能を使用する

...反復を処理します。

サブシェルを介して明示的なファイルリストを繰り返し処理し、expandを呼び出してstdoutに出力し、個々のファイルを上書きしたいと思っていました。 この回答で対処される問題

find $(git ls-files | grep '.py$') \
    -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;

このスレッドの他の回答は汎用的な解決策を提供していないので、私はその回答のわずかに変更されたバージョンを公開します。これは私が見た中で動作する唯一のものであり、ファイルパスを反復するときにのみ適用されます。

Findを使用してその名前を反復できるように、反復項目にちなんで名付けられたファイルを乱用して作成するソリューションを想像できます。


失敗した試行:

そのため、find exec呼び出しと同様に、forループ内でbash -c ...を使用してみました。しかし、出力ファイルが空になるという同じ問題に遭遇しました。

免責事項:私の問題が正確に何であるかわかりません、find execを使用する前のすべての試みで、書き込みが予想されていたすべての出力ファイルが上書きされ、私の問題はその後は空のファイルでした。

0
ThorSummoner