回答:
bashまたはkshで、ファイル名を配列に入れ、その配列を逆順に繰り返します。
files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
bar "${files[$i]}"
done
上記のコードksh_arraysは、オプションが設定されている場合(kshエミュレーションモードの場合)、zshでも機能します。zshには、glob修飾子を使用して一致の順序を逆にする、より簡単な方法があります。
for f in /var/logs/foo*.log(On); do bar $f; done
POSIXには配列が含まれていないため、移植性が必要な場合、文字列の配列を直接格納する唯一のオプションは位置パラメーターです。
set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
eval "f=\${$i}"
bar "$f"
i=$((i-1))
done
iとf; は必要ありません。を実行しshift、$1あなたの呼び出しに使用し、あなたのでbarテストし[ -z $1 ]ますwhile。
[ -z $1 ]も[ -z "$1" ]有用ではありません(パラメーターが*、または空の文字列だった場合はどうでしょうか?)。いずれにせよ、彼らはここで助けにはなりません。問題は、逆の順序でループする方法です。
改行を「ファンキーな文字」と見なさない限り、これを試してください。
ls /var/logs/foo*.log | tac | while read f; do
bar "$f"
done
f私の状況では、最も投票された回答が変数を破壊しました。ただし、この答えは、通常のfor回線のドロップイン置換として機能します。
誰かがスペースで区切られた文字列リストを反復処理する方法を見つけようとしている場合、これは機能します:
reverse() {
tac <(echo "$@" | tr ' ' '\n') | tr '\n' ' '
}
list="a bb ccc"
for i in `reverse $list`; do
echo "$i"
done
> ccc
> bb
> a
tacGNU coreutilsの一部であるので、それは一種の衝撃的です。しかし、あなたのソリューションも良いものです。
tac。tacここで-less応答の数から、OSXにはtacがないのではないかと思います。その場合、@ arpのソリューションのバリアントを使用してください-とにかく理解しやすいです。
find /var/logs/ -name 'foo*.log' -print0 | tail -r | xargs -0 bar
あなたが望むように動作するはずです(これはMac OS Xでテストされており、以下の警告があります...)。
findのmanページから:
-print0
This primary always evaluates to true. It prints the pathname of the current file to standard output, followed by an ASCII NUL character (charac-
ter code 0).
基本的に、文字列+ globに一致するファイルを見つけて、それぞれをNUL文字で終了します。ファイル名に改行またはその他の奇妙な文字が含まれている場合、findはこれを適切に処理する必要があります。
tail -r
パイプを通して標準入力を受け取り、それを反転させる(なお、tail -r印刷物のすべての標準的なデフォルトである標準出力への入力の、だけではなく、最後の10行、。man tail詳細は)。
次に、それをパイプしxargs -0ます:
-0 Change xargs to expect NUL (``\0'') characters as separators, instead of spaces and newlines. This is expected to be used in concert with the
-print0 function in find(1).
ここで、xargsは引数をNUL文字で区切って表示することを想定しています。NUL文字はから渡されfind、で反転されtailます。
私の警告:nullで終わる文字列ではうまく動作しないと読んだことtailがあります。これはMac OS Xではうまくいきましたが、すべての* nixに当てはまることを保証することはできません。慎重に踏んでください。
また、GNU Parallelがxargs代替手段としてよく使用されることにも言及する必要があります。あなたもそれをチェックアウトできます。
私は何かを逃しているかもしれないので、他の人がチャイムする必要があります
tail -rていないようですが...何か間違っていますか?
tac私はそれをしようとして代わりに、代替として
tail -rOSXに固有であり、ヌル区切りの入力ではなく、改行区切りの入力を反転します。2番目のソリューションはまったく機能しません(入力をlsにパイプしているので、気にしません)。確実に動作させる簡単な修正はありません。
あなたの例では、いくつかのファイルをループしていますが、配列のループをカバーしたり、任意の数の順序に基づいて反転したりすることもできるより一般的なタイトルのため、この質問を見つけました。
Zshでこれを行う方法は次のとおりです。
配列内の要素をループしている場合は、この構文を使用します(source)
for f in ${(Oa)your_array}; do
...
done
O次のフラグで指定された順序の逆。a通常の配列順序です。
@Gillesが言ったようにOn、例えばを使用して、globedファイルを逆順にしますmy/file/glob/*(On)。それOnは「名前の逆順」だからです。
Zshソートフラグ:
a 配列順序L ファイル長l リンクの数m 変更日n 名^o逆順(o通常順)O 逆順例については、https://github.com/grml/zsh-lovers/blob/master/zsh-lovers.1.txtおよびhttp://reasoniamhere.com/2014/01/11/outrageously-useful-tips-を参照してください。 to-master-your-z-shell /
Mac OSXはこのtacコマンドをサポートしていません。@tcdylによる解決策は、forループ内で単一のコマンドを呼び出すときに機能します。他のすべてのケースでは、次の方法が最も簡単に回避できます。
このアプローチでは、ファイル名に改行を含めることはできません。根本的な理由は、tail -r改行で区切られた入力をソートすることです。
for i in `ls -1 [filename pattern] | tail -r`; do [commands here]; done
ただし、改行の制限を回避する方法があります。ファイル名に特定の文字(「=」など)が含まれていないことがわかっている場合は、trすべての改行を置換してこの文字になり、ソートを実行できます。結果は次のようになります。
for i in `find [directory] -name '[filename]' -print0 | tr '\n' '=' | tr '\0' '\n'
| tail -r | tr '\n' '\0' | tr '=' '\n' | xargs -0`; do [commands]; done
注:のバージョンによっては、キャラクターとしてtrサポートさ'\0'れない場合があります。これは通常、ロケールをCに変更することで回避できます(ただし、修正後はコンピューター上で動作するようになったため、正確に覚えていません)。エラーメッセージが表示され、回避策が見つからない場合は、コメントとして投稿してください。トラブルシューティングのお手伝いをいたします。
sort -r前にパイプするforか、洗濯してくださいls -r。