回答:
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
tac
GNU 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 -r
OSXに固有であり、ヌル区切りの入力ではなく、改行区切りの入力を反転します。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
。