パイプライン命令に算術を適用する

パイプライン命令に算術を適用する

これまで私はこれを持っています:

sudo find /path/to/dir -type f |
  xargs -d "\n" sudo stat -c "%Y %n" | 
    {arithmetic to check if %Y is between 1685518962 and 1685624474??} | 
      {show file path}

参考までに、私は知っていますが、find -newermtコマンドラインで算術を実行することについてより一般的に質問されます。

明確にするために、私は行を望んだ。

TCSHやBASHも大丈夫ですが、他のシェルを教えてくれてありがとう。

答え1

ファイルのリストを処理するには、NULで区切られたレコード(-print0for find-0for xargs)を使用します。改行はファイルパスの他の文字(または非文字)で有効なためです。

すでにGNU拡張機能を使用しているので、次のことができます。

sudo find /path/to/dir -type f '(' \
   -newermt @1685518962 ! -newermt @1685624474 -exec something with {} + \
   -o -exec something-else with {} + ')'

GNUコマンドが導入される前に、GNUはfind(より良いインターフェースを介して)ファイルからメタデータを報告することができました。stat後処理では、gawk/mawk、perl、zsh など、NUL で区切られたレコードおよび浮動小数点演算をサポートするツールを使用できます。

sudo find -H /path/to/dir -type f -printf '%T@\0%p\0' |
  LC_ALL=C gawk -v RS='\0' -F: '
    {mtime = $0; getline file}
    mtime > 1685518962 && mtime <= 1685624474 {
      # something with mtime and file
    }'

そしてperl

sudo find -H /path/to/dir -type f -printf '%T@\0%p\0' | perl -0lne '
  $mtime = $_; $file = <>;
  if ($mtime > 1685518962 && $mtime <= 1685624474) {
    # something with $mtime and $file
  }'

ここに提供されている例を含むすべてのコードを1行に配置できます。ゴルフ練習なら、perl次の中で最も適しています。

sudo find -H /path/to/dir -type f -printf '%p\0%T@\0'|perl -0lne'$m=<>;{...}if$m>1685518962&&$m<=1685624474'

または使用している場合は、zshこれらのファイルを処理するためにシェルが必要な場合:

sudo find -H /path/to/dir -type f -printf '%T@/%p\0' |
  while IFS=/ read -rd '' mtime file; do
    (( mtime > 1685518962 && mtime <= 1685624474 )) &&
      something with $mtime and $file
  done

それでも、zshほとんどの機能が組み込まれていますが、GNUismには依存しませんが、おそらく遅くなる組み込みfind機能stat(GNU以前のバージョン)もあります。stat

sudo zsh -c '
  zmodload zsh/stat
  for file ( /path/to/dir/**/*(ND.) ) {
    stat -LF %s.%N -A mtime +mtime -- $file &&
      (( mtime > 1685518962 && mtime <= 1685624474 )) &&
      something with $file and $mtime
  }'

今日、私はtcshを使用して安定して作業を行うことはほとんど不可能なので、使用しません。しかし、あなたが言及したので、tcshは再帰ワイルドカードをサポートしていることに注意してください(2010年bashの直後にzshからコピーされます)。 -ファイルのmtime検索をサポートしますが、1秒未満の精度はサポートせず(算術はとにかく整数のみ可能です)、シンボリックリンク確認後にのみ可能です。

set globstar globdot
foreach file ( /path/to/dir/** )
  if ( -f $file:q && ! -l $file:q ) then
    @ mtime = -M $file:q
    if ( $mtime > 1685518962 && $mtime <= 1685624474 ) then
      something with $file:q and $mtime
    endif
  endif
end

他の人は完全なナノ秒精度でmtimeを取得しますが、浮動小数点タイプと//double結果を使用するほとんどのコンピュータ/ Cコンパイラは、今日のタイムスタンプに必要な精度を維持できません。awkperlzsh

たとえば、ほとんどは最後に変更されたファイルがどこにあるかを報告しません1685518962.000000001。これはあなたにとって大きな問題ではないかもしれません。たとえば、特定のマイクロ秒以内に最後に変更されたファイルを高精度で見つける必要がある場合などです。

また、注:環境変数は実行するコマンドにsudo渡され、その変数にはすべての引数が含まれているため失敗する可能性があります。SUDO_COMMANDxargs sudo cmd「人論が多すぎる」execve()ファイル数が多い場合は、パラメータと環境文字列の累積サイズが制限されているためエラーが発生するため、実行できますが、xargsその間に累積サイズが倍増して実行できない場合がありますsudosudocmd

この理由とsudo数回の呼び出しを実行するのに時間が節約されるため、ここでは1回だけ呼び出すこともできますsudo xargs cmdsudosudo sh -c '...'


¹これは、任意の精度算術が有効になっている場合は、任意の精度算術を使用するか、より一般的に秒とナノ秒を別々に比較するか(またはシェル/演算子が実行できます)、数値に数値を使用して-MvPREC=100最新バージョンのオプションで解決します。できます。固定サイズのバイナリに変換する代わりに文字列比較を実行します(たとえば、数値ソートパラメータ拡張フラグを使用する代わりにwithを使用)。gawk-Mbignumperl-newertmt[-nt() [[ $1 = ${${(n)@}[1]} ]] $t1 $t2(( t1 < t2 ))zshn

答え2

これは仕事のように聞こえますawk

sudo find /path/to/dir -type f |
  xargs -d "\n" sudo stat -c "%Y %n" |
  awk '$1 > 1685518962 && $1 < 1685624474 {print}'

次のオプションをxargs使用して削除できます。-execdirfind

sudo find /path/to/dir -type f -execdir stat -c "%Y %n" {} + |
  awk '$1 > 1685518962 && $1 < 1685624474 {print}'

答え3

まあ、bashは許可されています。

#!/bin/bash
shopt -s dotglob globstar extglob nullglob

oldest=1685518962
newest=1685624474

for file in **/*; do
  # check for regular file-ness
  modtime=$(stat -c '%Y' -- "${file}")
  [[ ( ! -L ${file} ) \
    && -f ${file} \
    && (  ${modtime} -gt ${oldest} ) \
    && (  ${modtime} -le ${newest} ) ]] \
  && {
    # do stuff
  }
done

Zshはglobbingが簡単にできることに少し可愛い

#!/usr/bin/zsh
zmodload zsh/stat

oldest=1685518962
newest=1685624474

for file in **/*(.ND); do
  modtime=$(zstat -L +mtime -- "${file}")
  [[  ${modtime} -gt ${oldest}  \
  &&  ${modtime} -le ${newest} ]] \
  && {
    # do stuff
  }
done

はい問題のため文字通り算術を要求すると、zshとbashの両方が拡張で算術をサポートすることを指摘します。$(( ${modtime} - ${oldest} ))下限秒以降の秒数を通知します。 Zshの算術関数は、特に浮動小数点では少し優れています。

答え4

他の回答の提案にもかかわらず一般的に言えば、パイプラインで使用できる 1 行シェル算術フィルタ関数を生成するには、2 つのコマンドを組み合わせる必要があります。

  1. xargs入力ラインをマッピングする機能、
  2. shシェル算術関数へのアクセス

パターンとしてxargs -L1 sh -c '_() { ... }; _ "$@"'

具体的な例を見ると、次のようになります。

find ...
  | xargs stat ...
  | xargs -L1 sh -c '_() { [ 1685518962 -le $0 -a $0 -le 1685624474 ] && echo $@; }; _ "$@"'

これはここにあるような迅速で汚れた作業に役立ちます。ただし、データボリュームがある場合など、Map-Reduce機能を備えたツールを展開したいと思いますawk

関連情報