web-dev-qa-db-ja.com

コマンドでファイルを逆の時間順にリストし、それらを引数として別のコマンドに渡すにはどうすればよいですか?

1つのコマンドラインで引数としていくつかのファイルを取り込むプログラムがあります。ディレクトリ内のすべてのファイルを時間の逆順にリストして呼び出します。

例えば:

ディレクトリに次のファイルを時間の逆順で持っています

$ ls -tr
 Introduction.pdf  'Object-Oriented Data Model.pdf' 

プログラムを簡単に実行でき、

myprogram Introduction.pdf  'Object-Oriented Data Model.pdf' 

別のコマンドでファイル一覧を表示したいのですが。 1つのファイル名にスペースがあるため、これは機能しません。

myprogram $(ls -tr)

lsの出力を解析することはお勧めしません。 findが役立つかどうかはわかりません。

その後、私は何ができますか?

ありがとう。

7
Tim

GNUユーティリティの合理的な最新バージョンがある場合、それらにNULLで終了するデータを処理させることができます。これにより、空白や改行の影響を受けないパイプラインを構築できますデータ自体。

私のテストツールは/tmp/argsというクイックスクリプトです。

#!/bin/bash
echo "This is args with $# value(s)"
for f in "$@"; do echo "> $f <"; done

これは、コマンドラインで一連のファイル名をフィードする方法です。ファイル名の最終変更時刻順にソートされています。

find -type f -printf "%T@ %p\0" | sort -zn | sed -z 's/^[0-9.]* //' | xargs -0 /tmp/args

findコマンドは、各ファイル/パス名の前に、最後に変更された日付/時刻の小数秒での表現を付けます。これはsortによって処理され、最低(最も古い)から最高(最新)の順に並べられます。 sedは、ソートに使用した先の番号を取り除き、結果のファイル名のセットがxargsに渡されます。ファイル名から先頭の%pを省略したい場合は、%P./に置き換えます。

データの例

# "c d" contains a space; "e f" contains a newline; "h" has leading whitespace
touch a 'e
f' g ' h ' 'c d' b

結果の例

This is args with 6 value(s)
> ./a <
> ./e
f <
> ./g <
> ./ h  <
> ./c d <
> ./b <
5
roaima

Bash まだ変更時間でファイルをソートすることは簡単ではありません なので、ここに必須のzshベースの答えがあります。その機能を使用するために、ログインシェルとしてzshに切り替える必要はありません。

ここでは、1つまたは2つの引数を受け取るラッパー関数を設定します。最初の引数は実行するプログラムです(例:myprogram); 2番目のオプションの引数は、プログラムに渡すファイルを含むディレクトリです。 2番目の引数を指定しない場合、デフォルトで現在のディレクトリが使用されます。

zeio() {
  # Zsh-based Execute with files In Order
  [ -d "${2:-.}" ] || return
  zsh -c "$1 \"${2:-.}\"/*(.om)"
}

もちろん、好きな名前を付けてください。 2番目の引数(ここでも、デフォルトで現在のディレクトリである.にデフォルト設定されています)の健全性チェックを行った後、プログラムといくつかの初期引数(引数#1)を含む単一引用符で囲まれた文字列でzshを呼び出します。ディレクトリ(引数#2)—デフォルトは.です—末尾の括弧に2つの "glob qualifiers" を含むワイルドカード/ glob拡張を使用します:

  1. .-通常のファイルである必要があります(ディレクトリやシンボリックリンクなどは不可)
  2. om-order(ソート)結果のリストを変更時間順に、最新のものから

ここで実際の作業をすべて行うのは、そのomグロブ修飾子です。

ここにいくつかのサンプル実行があります。 myprogは、受け取った引数を順番に示す単純なシェルスクリプトです。

#!/bin/sh
for arg do
  printf 'Arg: ->%s<-\n' "$arg"
done

go.shは、関数を保存したファイルです。残りのディレクトリ構造は次のとおりです。

$ tree .
.
├── dir1
│   ├── 203142
│   ├── 203143
│   └── 203144
├── dir3
│   ├── first\012filename
│   ├── this is 3rd
│   └── this is second
├── dir two
│   ├── 203225
│   ├── 203226
│   └── 203227
├── go.sh
└── myprog

...ここで、リストされたシーケンスの各サブディレクトリに3つのファイルのセットを作成しました。関数を実行すると、同じ順序で表示されることを期待しています。 dir3の下の最初のファイル名には改行があり、tree\012で表されます。結果は次のとおりです。

Default-to-current-directory動作のデモ:

$ zeio ./myprog
Arg: ->./myprog<-
Arg: ->./go.sh<-

通常のファイル名のデモ

$ zeio ./myprog dir1
Arg: ->dir1/203142<-
Arg: ->dir1/203143<-
Arg: ->dir1/203144<-

ディレクトリにはスペースがあります

$ zeio ./myprog "dir two"
Arg: ->dir two/203225<-
Arg: ->dir two/203226<-
Arg: ->dir two/203227<-

ファイル名には空白が含まれています

$ zeio ./myprog dir3
Arg: ->dir3/first
filename<-
Arg: ->dir3/this is second<-
Arg: ->dir3/this is 3rd<-
4
Jeff Schaller
(IFS=$'\n'; set -f; your_program $(ls -tr))

ファイル名に改行が含まれていないと仮定します。

例:

% touch 'a   b'
% touch 'c d'
% touch '*'
% (IFS=$'\n'; set -f; printf '%s\n' $(ls -tr))
e    f
a   b
c d
*

$'...'文字列をサポートしない標準シェルのバリアント:

(IFS='
' ; set -f; your_program $(ls -tr))

単純なpythonラッパー。改行を含むファイル名でも機能します。使用方法はthis_wrapper your_program *です。

#! /usr/bin/python
import os
import sys

sys.argv[2:] = sorted(sys.argv[2:], key=os.path.getmtime)
os.execvp(sys.argv[1], sys.argv[1:])
3
Uncle Billy