単一のコマンドを使用して、「ls」が何かを出力するかどうかを確認できますか?

単一のコマンドを使用して、「ls」が何かを出力するかどうかを確認できますか?

TL/DR:私はSolaris 10で働いています。コマンドがあり、ls ... | egrep ...そのコマンドがどのような結果を出力するかを知る必要があります。| wc -c最後に1つを追加できますが、出力ではなく終了コードに結果(0または0以外)が必要です。そして私はそれを使用できませんif。それはbashスクリプトではなく、1つのコマンドしか実行できません。


長いバージョン:私はSolaris 10システムで古いログファイルを圧縮して削除するためのメンテナンス手順を作成しています。指定されたパス内のすべての.logまたは.xmlファイルを確認し、指定された月に最後に変更されたファイルをインポートし、そのファイルで.tarを作成してから元のファイルを削除します。

ls -Egopqt /path/ | egrep -i '2016-10-[0123][0-9] .*(\.log$|\.xml$)' | awk '{ print $7 }'
| xargs tar -cvf target.tar

ファイルの削除も同じように機能します。最後の部分を次に変更します。| xargs -i rm {}

複雑すぎると思うかもしれませんが、効果があるファイルがない場合特定の月に該当する場合は、エラーメッセージが表示されますtar: Missing filenames。 tarを生成する前にどのように確認しますか?私はこんなことを考えました。wc を使用して出力があることを確認します。:

ls ... | egrep ... | wc -c

0ファイルが存在しない場合は正しく出力され、それ以外の場合は別の番号が出力されます。問題は次のとおりです。出力はなく、終了コードのみが表示されます。(エラーがないため常に0です。)Bashスクリプトでこれを行うのではなく、Siebel CRMを使用しています。コマンドを生成し、以下を使用して実行するjavascript関数があります。図書館システム着信電話。私が見ることができる唯一のものは終了コードです。0正常を意味し、ゼロ以外はエラーを意味します(「ゼロ以外」ではない実際の数字が表示されます)。

以前は、次の点を確認する必要がある同様の要件がありました。一つファイルが存在するかどうかこの回答これを行うのに役立ちました。

[ -f filename ] && exit 111 || exit 0

ファイル名が存在するかどうかによって、または111正常に取得されます。ただし、コマンドとして機能させる0ことはできません。ls ... | egrep ... | wc使ってみました。この文法:

[[ $( ls -Egopq /path/ | egrep -i ... | wc -c ) -ne 0 ]] && exit 111 || exit 0

しかし、私はいつもコード2で終了します。ファイルがあるかどうかは問題ではありません。私は何が間違っていましたか?


PS:チェックを実行し、簡単な方法でif出力を比較し、目的の終了コードを返す小さなシェルスクリプトを書くことができることを知っています。また、私は実際にできるコマンドの出力にアクセスするには、それをjavascriptにリダイレクトしてから> tempfileSiebelから読み取ることができます。ただし、不要な(一時的または永続的な)ファイルの生成を避けたいので、両方のオプションを避けることをお勧めします。

答え1

egrep一致する行がない場合は、ゼロ以外の値を返します。

答え2

xargsマニュアルから:

--no-run-if-empty
-r     If  the standard input does not contain any nonblanks, do not run the command.  
       Normally, the command is run once even if there is no input.  This option is a GNU extension.

... | xargs -r tar -cvf target.tarこれは問題を解決するようです!

答え3

このlsコマンドは、ユーザーに情報を提供するために微調整されています。つまり、安定して解析できる出力を生成するのには適していません。

代わりに使用を検討してくださいfind。つまり、あなたもそれを使用しないことを意味しますgrep

たとえば、.DeleteMe名前が 1 週間以上で終わるすべてのファイルを削除するには、次のようにします。

find /path -name '*.DeleteMe' \
           -mtime +6 \
           -exec rm -f -- {} +

それが何をするかを見るには、-exec rmに置き換えてください-exec echo rm

(* 1)に関連する他の方法とは異なり、この方法の利点は、xargs奇妙な文字を含むファイル名に会っても奇妙なことをしないことです。

次の場合に追加の措置を講じたい場合:いいえファイルを一致させ、ファイルのリストを一時ファイルに書き込み、ファイルが空であることを確認するのは非常に簡単です。

find /path -name '*.DeleteMe' \
           -mtime +6 \
           -exec rm -f -- {} + \
           -print > list_of_files$$
if ! [ -s list_of_files$$ ] ; then
    echo There were no matching files
fi
rm -f list_of_files$$

最初のファイルの前にいくつかの追加操作を実行する必要がある場合

find /path -name '*.DeleteMe' \
           -mtime +6 \
           -exec sh -c '
               o=$0   # at_least_one$$ from the outer shell
               [ -e $o ] || do_before_stuff
               > $o
               for f do
                   do_something with "$f"
               done
           ' at_least_one$$ {} +
if [ -e at_least_one$$ ] ; then
    do_after_stuff
else
    do_no_files_stuff
fi
rm -f at_least_one$$

もちろん、これは単純化された例です。複雑な作業を行う場合は、sh -c 'code here'スクリプトを作成して代わりに呼び出すことを検討してください。

あなたの具体的な質問については、次のように書きます。

find /path/ -name '2016-10-[0123][0-9]*' \
             \( -name '*.log' -o -name '*.xml' \) \
            -exec tar -cvf target.tar {} +

私はこれがこれまでに示した他のすべての方法と同じ失敗モードを持っていることを知りました。ファイルのリストがコマンドラインに比べて長すぎる場合、繰り返し呼び出され、最後のtar数個のファイルのみを含むタールボールを生成できます。

この問題を解決するには、以下を使用することをお勧めしますcpio

find /path/ -name '2016-10-[0123][0-9]*' \
             \( -name '*.log' -o \
                -name '*.xml' \) \
            -print |
cpio -o > target.cpio.trial
if [ -s target.cpio.trial ]
then mv target.cpio.trial target.cpio
else rm target.cpio.trial
fi

一部のバージョンではcpio-Hをサポートしています。滞在これは、次のように抽出できるtarballを作成するように指示できることを意味します。それ以外の場合は、必要に応じてファイルを抽出する必要がありますtar(あなたのバージョンがcpio形式のアーカイブを理解していない限り)。cpiotar

(脚注* 1:良いです。GNU findとGNU xargsがある場合、これはGNU findとGNU xargsとfind ... -print0 | xargs -0r cmd ...同じくらい安定していfind ... -exec cmd {} +ますが、これがあれば他のより良いオプションがあります。)

関連情報