파이프라인 명령에 산술 적용

파이프라인 명령에 산술 적용

지금까지 나는 이것을 가지고 있습니다 :

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
  }'

여기에 제공된 예제를 포함한 모든 코드는 한 줄에 배치할 수 있습니다. 골프 연습이라면 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실행할 수는 있지만 그 사이에 누적 크기가 두 배로 늘어나서 실행하지 못할 sudo수도 있습니다 .sudocmd

이러한 이유와 sudo몇 번의 호출을 실행하는 데 시간이 절약되므로 여기에서는 를 한 번만 호출 sudo xargs cmd할 수도 있습니다.sudosudo sh -c '...'


¹ 이는 임의 정밀도 산술이 활성화된 경우 임의 정밀도 산술을 사용 하거나 더 일반적으로 초와 나노초를 개별적으로 비교하거나( 또는 shells/ 의 연산자가 수행할 수 있음) 숫자에 숫자를 사용하여 -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. 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.

관련 정보