예

나는 현재 사용하고 있습니다

watch head -n 17 *

작동하지만 17일 이전의 모든 줄도 표시됩니다. 기본적으로 현재 방법으로 표시된 각 파일의 마지막 줄을 표시하고 싶습니다. 어떻게 해야 하나요?

예를 들어 행 수를 줄여보겠습니다. 7로. 그래서:

예시 파일:

1
2
3
4
5
6
7
8

이 줄은:

watch head -n 7 *

산출

1
2
3
4
5
6
7

내가 원하는 곳:

7

답변1

GNU 사용 awk:

watch -x gawk '
  FNR == 17 {nextfile}
  ENDFILE   {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}' ./*

출력은 다음과 같습니다.

        ./file1[17] line17
  ./short-file2[05] line 5 is the last

glob은 ./*호출 시 한 번만 확장됩니다.watch

귀하의 watch head -n 17 *취약점은 확장이 *실제로 쉘에 의해 쉘 코드로 해석되어 watch인수를 공백으로 연결하기 때문에 임의의 명령 주입 취약점입니다.

현재 디렉터리의 파일 이름이 이면 $(reboot)다시 시작됩니다.

를 사용하면 쉘을 건너뛰고 명령을 직접 실행하도록 -x지시합니다 . watch또는 다음을 수행할 수 있습니다.

watch 'exec gawk '\''
  FNR == 17 {nextfile}
  ENDFILE   {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}'\'' ./*'

각 반복에서 glob을 확장 watch하는 쉘을 실행하는 데 사용됩니다 . 실제로 와 동일합니다 . 를 사용하면 원하는 셸을 지정할 수 있습니다. 예를 들어 재귀 글로빙을 수행하고 일반 파일로 제한할 수 있는 보다 강력한 셸을 선택할 수 있습니다../*watch foo barwatch -x sh -c 'foo bar'watch -xzsh

watch -x zsh -c 'awk '\''...'\'' ./**/*(.)'

그렇지 않은 경우 gawk에도 다음을 수행할 수 있습니다.

watch '
  for file in ./*; do
    [ -s "$file" ] || continue
    printf "%s: " "$file"
    head -n 17 < "$file" | tail -n 1
  done'

다음과 같은 출력을 제공합니다.

./file1: line17
./short-file2: line 5 is the last

그러나 이렇게 하면 파일당 여러 명령을 실행하므로 효율성이 떨어집니다.

답변2

다음 두 가지 예를 결합하고 head다음과 같이 하십시오.tail

$ seq 1 80 | head -n 17 | tail -n 1
17

$ seq 1 10 | head -n 17 | tail -n 1
10

따라서 실제 문제를 해결하기 위한 명령은 다음과 같습니다.

watch 'for f in *; do head -n 17 -- "$f" 2>/dev/null | tail -n 1 ; done'

2>/dev/null*는 읽기 권한이 없는 디렉터리 및 파일과 일치하여 숨기고 싶은 오류 메시지를 생성하므로 이 부분이 필요합니다.

답변3

find, exec, sed를 사용하는 또 다른 방법

watch find . -type f -name \"*\" -exec sh -c \'\( printf '%-50s ' {} \; sed -n 17p {}\)\' \\\;

관련 정보