디렉토리의 모든 기본 이름을 수정된 날짜별로 정렬하는 가장 안정적인 방법은 무엇입니까?

디렉토리의 모든 기본 이름을 수정된 날짜별로 정렬하는 가장 안정적인 방법은 무엇입니까?

다음을 포함하는 디렉토리가 제공됩니다.

  • note 1.txt, 어제 마지막으로 수정됨
  • note 2.txt, 마지막 수정은 그저께였습니다
  • note 3.txt, 오늘 마지막으로 수정됨

배열을 얻는 가장 좋은 방법은 무엇입니까 note 3 note 1 note 2?

"최고"를 정의하기 위해 저는 효율성과 이식성보다 견고성(macOS의 Zsh 환경에서)에 더 관심이 있습니다.

의도된 사용 사례는 수백 또는 수천 개의 일반 텍스트 파일을 포함하는 디렉터리이지만 (질문을 혼동할 위험이 있음) 이것은 내가 겪고 있는 보다 일반적인 문제, 즉 파일 경로에서 문자열을 실행하는 특정 사례입니다. 가장 좋은 방법은 ls, find및 와 같은 명령을 통해 인쇄하는 것입니다 mdfind.


나는 위의 목적을 달성하기 위해 이 명령을 호출하는 매크로를 사용해 왔습니다.

ls -t | sed -e 's/.[^.]*$//'

결코 실패하지 않지만,

  • 그렉의 위키출력을 구문 분석하지 않는 것이 좋습니다 ls. (분석하다ls;관행, '5. 절대 하지 마세요' 아래).
  • sed매개변수 확장이 가능한 곳을 호출하는 것은 비효율적인가요?

정렬되지 않은 목록을 생성하는 인수 확장 find(파일 경로를 안전하게 구분하려면 개행 대신 문자 사용 )을 사용하여 기본 이름을 추출합니다.NUL

find . -type f -print0 | while IFS= read -d '' -r l ; do print "${${l%.*}##*/}" ; done

하지만 수정된 날짜별로 정렬하려면 호출이 필요한 것 같고 statmacOS sort에는 태그가 find없기 때문입니다.-printf그렇지 않으면 잘 작동할 수도 있습니다..

마지막으로 Zsh를 사용하십시오.글로벌 예선:

for f in *(om) ; do print "${f%.*}" ; done

이식 가능하지는 않지만 이 마지막 접근 방식이 나에게는 가장 강력하고 효율적인 것 같습니다. 이 올바른지 find? 단순히 디렉토리에 파일을 나열하는 대신 실제로 검색을 수행할 때 위 명령의 수정된 버전을 사용하면 안되는 이유가 있습니까?

답변1

존재하다 zsh,

list=(*(Nom:r))

확실히 가장 튼튼합니다.

print -rC1 -- *(Nom:r)

한 줄에 하나씩 인쇄하거나

print -rNC1 -- *(Nom:r)

NUL은 파일 경로에 허용되지 않는 유일한 문자이므로 출력에서 ​​모든 작업을 수행할 수 있도록 NUL로 구분된 레코드로 사용됩니다.

*(N-om:r)수정 시간을 고려하려면 다음으로 변경하십시오.뒤쪽에심볼릭 링크 확인(대상의 런타임, 그런 심볼릭 링크가 아님 ls -Lt).

:r(을 위한뿌리cshname)은 확장을 제거하는 데 사용되는 기록 수정자( 의 )입니다 . .bashrc이 옵션이 활성화된 경우에만 빈 문자열이 됩니다 .dotglob

재귀적 으로 실행되도록 변경 **/*(N-om:t:r)(:t꼬리(기본 이름), 즉 디렉터리 구성 요소를 제거합니다.

임의의 파일 이름을 사용하여 이를 안정적으로 수행하는 것은 ls어려울 것입니다.

한 가지 접근 방식은 실행 ls -td -- ./*(파일 이름 목록이 인수 목록 제한을 준수한다고 가정)하고 해당 출력을 구문 분석하여 각 파일 이름이 로 시작한다는 사실을 기반으로 ./NUL 구분 목록 또는 셸 인용 목록을 생성하여 이를 셸에 전달하는 것입니다. 그러나 그것은 이식 가능합니다. 또한 perl또는 에서 도움을 구하지 않는 한 매우 고통스럽습니다 python.

그러나 신뢰할 수 있는 경우 perlNUL python로 구분된 출력을 사용하여 파일 목록을 생성하고 정렬하도록 할 수 있습니다(초 미만의 정밀도를 지원하려는 경우 이식하기가 쉽지 않을 수 있음).

ls -t | sed -e 's/.[^.]*$//'

개행 문자가 포함된 파일 이름에서는 제대로 작동하지 않습니다(IIRC 일부 macOS 버전에는 /etc기본적으로 이러한 파일 이름이 함께 제공됨). 유효한 문자를 형성하지 않는 바이트 시퀀스가 ​​포함된 파일 이름의 경우에도 실패하거나 .일치 [^.]하지 않을 수 있습니다. 하지만 macOS에서는 작동하지 않을 수 있으며 로케일을 C/ POSIX로 설정하여 문제를 해결할 수 있습니다 sed.

.( )는 s/\.[^.]*$//모든 문자와 일치하는 정규식 연산자이므로 이스케이프 해야 합니다 . 그렇지 않으면 점이 없는 파일을 foobar빈 문자열로 변환합니다.

문자열 인쇄에 유의하세요.날것의, 그것은:

print -r -- "$string"

print "$string"$string로 시작하는 값에 대해서는 실패하며 -명령 주입 취약점이 발생하더라도(예: 여기에서 string='-va[$(uname>&2)1]'무해한 uname명령을 사용하려고 시도하는 경우) 문자가 포함된 값을 파괴합니다 \.

당신의:

find . -type f -print0 | while IFS= read -d '' -r l ; do print "${${l%.*}##*/}" ; done

또 다른 문제는 당신이 옷을 벗었다는 것입니다.* 앞으로디렉터리 구성 요소를 제거합니다. 예를 들어 a는 ./foo.d/bar대체되어 foo빈 문자열이 bar됩니다 ../foo

find다양한 셸에서 출력을 처리하는 안전한 방법은 다음을 참조하세요.찾기 결과를 반복하는 것이 왜 나쁜 습관입니까?

답변2

IMNSHO 견고성과 쉘 스크립팅은 호환되지 않는 개념입니다(IFS는 단지 해킹일 뿐입니다. 죄송합니다). 나는 당신이 원하는 것을 강력한 방식으로 달성하는 방법은 두 가지 밖에 없다고 생각합니다. 정상적인 언어(Python, C 등)로 프로그램을 작성하거나 견고성을 위해 특별히 제작된 도구를 사용하는 것입니다.

csv-nix-tools(*)를 사용하면 다음과 같이 이를 달성할 수 있습니다.

csv-ls -c name,mtime_sec,mtime_nsec | 
csv-sort -c mtime_sec,mtime_nsec | 
csv-cut -c name |
csv-add-split -c name -e . -n base,ext -r | 
csv-cut -c base |
csv-header --remove

꽤 자명합니다.

파일의 기본 이름만 보고 싶은 경우에는 이것으로 충분하지만 일반적으로 방금 얻은 데이터를 사용하여 유용한 작업을 수행하려는 경우가 많습니다. 이것이 바로 싱크 도구의 목적입니다. 현재 csv-exec(각 줄에서 명령 실행), csv-show(사람이 읽을 수 있는 형식으로 데이터 형식 지정) 및 csv-plot(gnuplot을 사용하여 2D 또는 3D 그래픽 생성)의 세 가지가 있습니다.

아직 부족한 부분이 있지만 도구는 사용을 시작할 수 있을 만큼 충분히 좋습니다.

(*)https://github.com/mslusarz/csv-nix-tools

답변3

GNU 도구가 있는 시스템에서 상당히 광범위한 ksh 확장(bash 및 zsh 포함)을 사용하는 모든 셸에서 작동하는 다른 방법이 이미 다루어지지 않았다는 사실에 놀랐습니다.

while IFS= read -r -d ' ' time && IFS= read -r -d '' filename; do
  printf 'Filename %q, with epoch time %s\n' "$filename" "$time"
done < <(find . -mindepth 1 -maxdepth 1 -printf '%T@ %P\0' | sort -gz)

작동 방식을 설명하세요.

  • 형식 find문자열은 %T@ %P\0각 파일에 대해 10진수 타임스탬프(선택적 1초 미만 정밀도 포함), 공백, 파일의 기본 이름, NUL을 인쇄합니다.
  • 에서는 부동 소수점 값의 일반화된 순서가 올바르게 처리되며 sort -gz구분 기호로 개행 문자 대신 NUL이 예상됩니다.-g-z
  • 에서는 IFS= read -r -d ' ' time && IFS= read -r -d '' filename첫 번째 공백에서 시간 읽기를 종료하고 첫 번째 NUL에서 파일 이름 읽기를 종료합니다.
  • 형식 문자열을 사용하여 결과를 인쇄할 때 %q파일 이름에 있는 인쇄할 수 없는 문자(탭, 줄 바꿈, 캐리지 리턴 등)도 읽을 수 있는 텍스트로 변환합니다 .

관련 정보