Bash에서는 특정 패턴과 일치하는 최신 파일의 파일 이름을 반환하는 함수를 만들고 싶습니다. 예를 들어 다음과 같은 파일 디렉토리가 있습니다.
Directory/
a1.1_5_1
a1.2_1_4
b2.1_0
b2.2_3_4
b2.3_2_0
'b2'로 시작하는 최신 파일을 원합니다. bash에서 어떻게해야합니까? 내 ~/.bash_profile
스크립트에 이것을 가지고 있어야합니다 .
Bash에서는 특정 패턴과 일치하는 최신 파일의 파일 이름을 반환하는 함수를 만들고 싶습니다. 예를 들어 다음과 같은 파일 디렉토리가 있습니다.
Directory/
a1.1_5_1
a1.2_1_4
b2.1_0
b2.2_3_4
b2.3_2_0
'b2'로 시작하는 최신 파일을 원합니다. bash에서 어떻게해야합니까? 내 ~/.bash_profile
스크립트에 이것을 가지고 있어야합니다 .
답변:
이 ls
명령에는 -t
시간별로 정렬 할 매개 변수 가 있습니다. 그런 다음을 사용하여 첫 번째 (최신)를 가져올 수 있습니다 head -1
.
ls -t b2* | head -1
그러나주의하십시오 : 왜 ls의 출력을 파싱해서는 안됩니까?
내 개인적인 의견 : 파싱 ls
은 파일 이름에 공백이나 줄 바꿈과 같은 재미있는 문자가 포함될 수있는 경우에만 위험합니다. 파일 이름에 재미있는 문자가 포함되어 있지 않다고 보장하면 구문 분석 ls
이 매우 안전합니다.
많은 다른 상황에서 많은 시스템에서 많은 사람들이 실행할 스크립트를 개발하고 있다면 구문 분석하지 않는 것이 좋습니다 ls
.
"올바르게"하는 방법은 다음과 같습니다 . 디렉토리에서 최신 (최신, 초기, 가장 오래된) 파일을 어떻게 찾을 수 있습니까?
unset -v latest
for file in "$dir"/*; do
[[ $file -nt $latest ]] && latest=$file
done
ls
, printf "%s\n" b2* | head -1
당신을 위해 그것을 할 것입니다.
b2.10_5_2
으로도이 솔루션을 죽입니다.
의 조합 find
과 ls
잘 작동
해결책:
find . -name "my-pattern" -print0 |
xargs -r -0 ls -1 -t |
head -1
그것을 분해하자 :
다음과 find
같이 흥미로운 파일을 모두 일치시킬 수 있습니다.
find . -name "my-pattern" ...
그런 다음 -print0
모든 파일 이름을 다음 ls
과 같이 안전하게 전달할 수 있습니다 .
find . -name "my-pattern" -print0 | xargs -r -0 ls -1 -t
추가 find
검색 매개 변수 및 패턴을 여기에 추가 할 수 있습니다
find . -name "my-pattern" ... -print0 | xargs -r -0 ls -1 -t
ls -t
수정 시간 (가장 먼저)별로 파일을 정렬하여 한 줄에 하나씩 인쇄합니다. -c
생성 시간을 기준으로 정렬하는 데 사용할 수 있습니다 . 참고 : 이것은 줄 바꿈이 포함 된 파일 이름으로 중단됩니다.
마지막으로 head -1
정렬 목록에서 첫 번째 파일을 가져옵니다.
참고 : xargs
인수 목록의 크기에 시스템 제한을 사용하십시오. 이 크기를 초과하면 여러 번 xargs
호출 ls
됩니다. 이것은 정렬과 아마도 최종 출력을 깨뜨릴 것입니다. 운영
xargs --show-limits
시스템의 한계를 확인하십시오.
참고 2 :find . -maxdepth 1 -name "my-pattern" -print0
하위 폴더를 통해 파일을 검색하지 않으려면 사용 하십시오.
참고 3 : @ starfry-ar에 의해 지적 된 바와 같이에 -r
대해 일치하는 파일이없는 경우에 xargs
대한 호출을 막는 ls -1 -t
것 find
입니다. 제안 해 주셔서 감사합니다.
find . -name "my-pattern" ... -print0
제공find: paths must precede expression: `...'
...
"추가 매개 변수"를 나타냅니다. 필요하지 않으면 생략하십시오.
-r
xargs 명령 줄 에 추가 하여 xargs가 표준 입력에서 아무 것도받지 않으면 명령 줄을 실행하지 않도록 지시하는 것입니다.
-r
대답에 덧붙였다 .
이것은 필요한 Bash 함수의 가능한 구현입니다.
# Print the newest file, if any, matching the given pattern
# Example usage:
# newest_matching_file 'b2*'
# WARNING: Files whose names begin with a dot will not be checked
function newest_matching_file
{
# Use ${1-} instead of $1 in case 'nounset' is set
local -r glob_pattern=${1-}
if (( $# != 1 )) ; then
echo 'usage: newest_matching_file GLOB_PATTERN' >&2
return 1
fi
# To avoid printing garbage if no files match the pattern, set
# 'nullglob' if necessary
local -i need_to_unset_nullglob=0
if [[ ":$BASHOPTS:" != *:nullglob:* ]] ; then
shopt -s nullglob
need_to_unset_nullglob=1
fi
newest_file=
for file in $glob_pattern ; do
[[ -z $newest_file || $file -nt $newest_file ]] \
&& newest_file=$file
done
# To avoid unexpected behaviour elsewhere, unset nullglob if it was
# set by this function
(( need_to_unset_nullglob )) && shopt -u nullglob
# Use printf instead of echo in case the file name begins with '-'
[[ -n $newest_file ]] && printf '%s\n' "$newest_file"
return 0
}
Bash 내장만을 사용하며 이름에 개행 문자 또는 기타 특이한 문자가 포함 된 파일을 처리해야합니다.
nullglob_shopt=$(shopt -p nullglob)
하고 나중에 이전의 $nullglob
상태를 되돌릴 수 있습니다 nullglob
.
$()
이 내장을 사용하는 경우에도 특히 Cygwin에서 느리기 때문에 명령 대체 ( 또는 백틱)를 사용하지 마십시오 . 또한 명령이 실행되는 서브 쉘 컨텍스트로 인해 명령이 예기치 않은 방식으로 작동 할 수 있습니다. 또한 변수 nullglob_shopt
값을 잘못 얻는 경우 매우 나쁜 일이 발생할 수 있으므로 명령을 변수 (예 :)에 저장하지 마십시오 .
cat
! 더 많은 작업이 필요하더라도 사람들 개념을 보여주는 이점이 있습니다. +1하세요!
비정상적인 파일 이름 (예 : 유효한 \n
문자를 포함하는 파일) 은 이런 종류의 구문 분석으로 혼란을 초래할 수 있습니다.
perl -le '@sorted = map {$_->[0]}
sort {$a->[1] <=> $b->[1]}
map {[$_, -M $_]}
@ARGV;
print $sorted[0]
' b2*
그것은 그곳에서 사용 된 슈바르츠 식 변환 입니다.
stat
파일 글로브와 함께 사용할 수 있으며 파일 시간이 앞면에 추가 된 데코 레이트-소트-장식되지 않습니다 :
$ stat -f "%m%t%N" b2* | sort -rn | head -1 | cut -f2-
stat
옵션을 올바르게 기억하고 있다면 Mac / FreeBSD 버전의 것일 수 있습니다 . 다른 플랫폼에서 유사한 결과를 얻으려면 다음을 사용할 수 있습니다.stat -c $'%Y\t%n' b2* | sort -rn | head -n1 | cut -f2-
find ... xargs ... head ...
위 의 솔루션 을 원 하지만 기능 양식을 사용하기 쉬운 사람들을위한 다크 매직 기능 주문은 다음과 같이 생각할 필요가 없습니다.
#define the function
find_newest_file_matching_pattern_under_directory(){
echo $(find $1 -name $2 -print0 | xargs -0 ls -1 -t | head -1)
}
#setup:
#mkdir /tmp/files_to_move
#cd /tmp/files_to_move
#touch file1.txt
#touch file2.txt
#invoke the function:
newest_file=$( find_newest_file_matching_pattern_under_directory /tmp/files_to_move/ bc* )
echo $newest_file
인쇄물:
file2.txt
어느 것이 :
주어진 디렉토리에서 파일의 가장 오래된 수정 된 타임 스탬프를 가진 파일 이름이 주어진 패턴과 일치합니다.
find 명령을 사용하십시오.
Bash 4.2 이상을 사용한다고 가정하면 -printf '%T+ %p\n'
파일 타임 스탬프 값에 사용하십시오.
find $DIR -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2
예:
find ~/Downloads -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2
보다 유용한 스크립트를 보려면 https://github.com/l3x/helpers에서 최신 스크립트 찾기를 참조 하십시오.
이를 달성하는 훨씬 더 효율적인 방법이 있습니다. 다음 명령을 고려하십시오.
find . -cmin 1 -name "b2*"
이 명령은 "b2 *"에서 와일드 카드 검색을 사용하여 정확히 1 분 전에 생성 된 최신 파일을 찾습니다. 지난 이틀 동안의 파일을 원한다면 아래 명령을 사용하는 것이 좋습니다.
find . -mtime 2 -name "b2*"
"." 현재 디렉토리를 나타냅니다. 도움이 되었기를 바랍니다.