전체 표준 입력에 표준 입력의 마지막 줄을 추가합니다.

전체 표준 입력에 표준 입력의 마지막 줄을 추가합니다.

다음 스크립트를 고려해보세요.

tmpfile=$(mktemp)

cat <<EOS > "$tmpfile"
line 1
line 2
line 3
EOS

cat <(tail -1 "$tmpfile") "$tmpfile"

이것은 작동하고 출력됩니다:

line 3
line 1
line 2
line 3

입력 소스가 실제 파일이 아니라 표준 입력이라고 가정합니다.

cat <<EOS | # what goes here now?
line 1
line 2
line 3
EOS

명령을 수정하는 방법:

cat <(tail -1 "$tmpfile") "$tmpfile"

그렇다면 다른 상황에서도 여전히 동일한 출력이 생성됩니까?

노트:내가 사용하고 있는 특정 Heredoc과 Heredoc 자체의 사용은 단지 예시일 뿐입니다. 허용되는 답변은 다음과 같다고 가정해야 합니다.stdin을 통해 임의의 데이터 수신.

답변1

노력하다:

awk '{x=x $0 ORS}; END{printf "%s", $0 ORS x}'

입력으로 변수를 정의합니다.

$ input="line 1
> line 2
> line 3"

다음 명령을 실행하세요.

$ echo "$input" | awk '{x=x $0 ORS}; END{printf "%s", $0 ORS x}'
line 3
line 1
line 2
line 3

물론 here-doc을 사용할 수도 있습니다.

$ cat <<EOS | awk '{x=x $0 ORS}; END{printf "%s", $0 ORS x}'
line 1
line 2
line 3
EOS
line 3
line 1
line 2
line 3

어떻게 작동하나요?

  • x=x $0 ORS

    그러면 입력의 각 줄이 변수에 추가됩니다 x.

    전혀 ORS그렇지 않습니다 .출력 레코드 구분 기호. 기본적으로 개행 문자입니다.

  • END{printf "%s", $0 ORS x}

    전체 파일을 읽은 후에는 마지막 줄이 인쇄되고 $0그 뒤에 전체 파일의 내용이 인쇄됩니다 x.

이는 입력 전체를 메모리로 읽어들이기 때문에 대규모(예를 들어기가바이트) 입력.

답변2

stdin이 검색 가능한 파일을 가리키는 경우(여기의 bash(다른 모든 쉘은 아님)에 대한 문서가 임시 파일로 구현됨) 전체 내용을 읽기 전에 꼬리를 가져온 다음 뒤로 검색할 수 있습니다.

찾다zsh연산자는 tcl/perl/python과 같은 쉘 또는 스크립팅 언어에서 사용할 수 있지만 ksh93사용해야 하는 경우 언제든지 더 높은 수준의 인터프리터를 호출할 수 bash있습니다 .bashbash

ksh93 -c 'tail -n1; cat <#((0))' <<...

또는

zsh -c 'zmodload zsh/system; tail -n1; sysseek 0; cat' <<...

이제 stdin이 검색할 수 없는 파일(예: 파이프 또는 소켓)을 가리키는 경우에는 작동하지 않습니다. 그렇다면 유일한 옵션은 전체 입력을 읽고 저장하는 것입니다(메모리나 임시 파일에...).

메모리 내 저장을 위한 일부 솔루션이 제공되었습니다.

임시 파일을 사용하려면 zsh다음과 같이 하세요.

seq 10 | zsh -c '{ cat =(sed \$w/dev/fd/3); } 3>&1'

Linux에서 여기에 설명된 대로 임시 파일을 사용하는 셸을 사용하는 경우 bash실제로 zsh이 문서에서 생성된 임시 파일을 사용하여 출력을 저장할 수 있습니다.

seq 10 | {
  chmod u+w /dev/fd/3 # only needed in bash5+
  cat > /dev/fd/3
  tail -n1 /dev/fd/3
  cat <&3
} 3<<EOF
EOF

답변3

cat <<EOS | sed -ne '1{h;d;}' -e 'H;${G;p;}'
line 1
line 2
line 3
EOS

이것을 사용되는 것으로 변환할 때의 문제점은 파일의 끝을 찾으려면 전체 파일을 읽어야 한다는 것 tail입니다 . tail파이프라인에서 이를 사용하려면 다음이 필요합니다.

  1. 문서의 전체 내용을 에 제공하십시오 tail.
  2. 그것을 제공하다다시도착하다 cat.
  3. 그와 같은 순서로.

까다로운 부분은 문서의 내용을 복사하는 것(그렇게 하는 것)이 아니라 tee중간 임시 파일을 사용하지 않고 문서의 나머지 부분이 출력되기 전에 출력을 얻는 것입니다.tail

사용 sed(또는 awk,John1024 정말요) 데이터를 메모리에 저장함으로써 데이터의 이중 구문 분석 및 정렬 문제를 제거합니다.

내가 제안하는 해결책 sed

  1. 1{h;d;}, 첫 번째 행을 예약된 공간에 그대로 저장한 후 다음 행으로 점프합니다.
  2. H, 개행 문자가 포함된 예약된 공간에 줄을 서로 추가합니다.
  3. ${G;p;}, 새 줄이 포함된 마지막 줄에 예약된 공간을 추가하고 결과 데이터를 인쇄합니다.

이것은 John1024의 솔루션을 문자 그대로 번역한 것이지만 sedPOSIX 표준은 최소 8192바이트(8KiB)의 예약된 공간만 보장한다는 점에 유의하세요.추천하다이 버퍼는 필요에 따라 동적으로 할당되고 확장됩니다. sedGNU와 BSD 모두 sed이를 수행합니다.


명명된 파이프를 사용하도록 허용하는 경우:

mkfifo mypipe
cat <<EOS | tee mypipe | cat <( tail -n 1 mypipe ) -
line 1
line 2
line 3
EOS
rm -f mypipe

tee이는 데이터를 아래로 보내는 mypipe동시에 데이터를 보내는 데 사용됩니다 cat. 유틸리티 cat는 먼저 출력을 읽은 다음 tail(읽기 mypipe에서 tee쓰기까지) 출력에서 ​​직접 문서 사본을 추가합니다 tee.

그러나 문서가 다음과 같은 경우에는 심각한 결함이 있습니다.너무 큰(파이프의 버퍼 크기보다 큼) (이름이 지정되지 않은) 파이프가 지워질 때까지 기다리는 동안 tee쓰기 mypipe및 차단됩니다. 읽기 전에는 지워지지 않습니다 cat. cat끝날 때까지 읽지 마세요 cat. tail그리고 tail그것이 끝날 때까지는 끝나지 않을 것입니다. tee이는 전형적인 교착 상태 상황입니다.

다양성

tee >( tail -n 1 >mypipe ) | cat mypipe -

같은 문제가 있습니다.

답변4

순서에 관심이 없다면. 그러면 이것이 작동할 것입니다 cat lines | tee >(tail -1). 다른 사람들이 말했듯이. 필요한 순서대로 작업을 수행하려면 파일을 두 번 읽거나 전체 파일을 버퍼링해야 합니다.

관련 정보