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: `...'
..."추가 매개 변수"를 나타냅니다. 필요하지 않으면 생략하십시오.
-rxargs 명령 줄 에 추가 하여 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*"
"." 현재 디렉토리를 나타냅니다. 도움이 되었기를 바랍니다.