bash에서 null로 구분된 입력에서 "머리"와 "꼬리"를 수행하는 방법은 무엇입니까?

bash에서 null로 구분된 입력에서 "머리"와 "꼬리"를 수행하는 방법은 무엇입니까?

find이 명령은 파일 이름을 null로 구분된 문자열( -print0제공된 경우)로 출력할 수 있으며 옵션이 켜진 상태에서 사용할 수 있습니다 xargs. -0그러나 그 사이에는 해당 파일 모음을 조작하기가 어렵습니다. sort명령에는 -z파일을 정렬할 수 있는 스위치가 있지만 head포함되지는 않습니다 tail.

이러한 null로 구분된 입력을 편리한 방법으로 어떻게 headAND 할 수 있습니까? tail(언제든지 짧고 느린 Ruby 스크립트를 만들 수 있지만 더 좋은 방법이 있기를 바랍니다)

답변1

GNU headtailcoreutils 버전 8.25부터 -z옵션이 있습니다.

이전 버전이나 GNU가 아닌 시스템의 경우 다음 \0과 같이 교체해 볼 수 있습니다 \n.

find ... -print0 |
  tr '\0\n' '\n\0' |
  head |
  tr '\0\n' '\n\0'

일부 head구현에서는 NUL 문자를 처리할 수 없지만(POSIX에서는 이를 요구하지 않음) find는 처리하며 -print0텍스트 head유틸리티는 일반적으로 NUL 문자를 지원합니다.

tr함수를 사용하여 두 s 사이의 명령을 래핑할 수도 있습니다 .

nul_terminated() {
  tr '\0\n' '\n\0' | "$@" | tr '\0\n' '\n\0'
}

find ... -print0 | nul_terminated tail -n 12 | xargs -r0 ...

아래의 nul_terminateda는 \0개행 문자를 나타냅니다. 예를 들어 \n다음으로 바꾸세요 _.

find . -depth -name $'*\n*' -print0 | nul_terminated sed '
  p;h;s,.*/,,;s/\x0/_/g;H;g;s,[^/]*\n,,' | xargs -r0n2 mv

( \x0또한 GNU 확장).

여러 개를 실행해야 하는 경우필터명령을 사용하면 다음과 같이 할 수 있습니다.

find ... -print0 |
  nul_terminated cmd1 |
  nul_terminated cmd2 | xargs -r0 ...

그러나 이는 일부 중복 tr명령을 실행하는 것을 의미합니다. 또는 다음을 실행할 수 있습니다.

find ... -print0 | nul_terminated eval 'cmd1 | cmd2' | xargs -r0 ...

답변2

이전 시스템에서는 null로 구분된 입력이 지원되었으므로 grep3개의 최신 파일을 가져오는 대신 이 작업을 수행했습니다.head --zero-terminated -n 3

find . -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zrn | grep -zm 3 ""

sort와 의 조합을 사용하면 grep대체를 통해 tail세 번째 최신 파일을 얻을 수 있습니다.

find . -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zrn | grep -zm 3 "" | sort -zn | grep -zm 1 ""

파일 이름만:

find . -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zrn | grep -zm 3 "" | sort -zn | grep -zPom 1 "(?s)/.*"

불행하게도 -o(일치만) 0으로 구분된 출력(버그!?)을 비활성화합니다. 이는 다음을 통해 활성화되고 -z끝 줄 바꿈이 있는 파일 이름을 반환하므로 추가 파이핑을 허용하지 않습니다.

find . -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zrn | grep -zm 3 "" | sort -zn | grep -zPom 1 "(?s)/.*" | xargs -0 ls -l
ls: cannot access /te
st
: No such file or directory

이 문제는 다음을 사용하여 해결할 수 있습니다 read.

find . -mindepth 1 -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zrn | grep -zm 3 "" | sort -zn | { IFS=" " read -rd '' mtime file && echo -en "$file\0"; } | xargs -0 -n1 ls -l
-rw-r--r-- 1 root root 0 Apr 24 17:46 ./te?st

( ls -t예상대로 파일 이름의 개행 문자에 대해 물음표를 반환합니다.)

또는 현재 디렉터리에서 가장 오래된 100개 파일을 가져오는 방법에 대한 또 다른 예는 다음과 같습니다.

find /tmp/test -mindepth 1 -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zn | grep -zm 10 "" | { while IFS=" " read -rd '' mtime file; do echo -en "$file\0"; done; } | xargs -0 -n1 ls -bl
-rw-r--r-- 1 root root 0 Mar 23 14:32 /tmp/test/foo\ baz.txt
-rw-r--r-- 1 root root 0 Apr 26 10:43 /tmp/test/foo\nbar\ baz.txt
...

관련 정보