추상적인:

추상적인:

파일의 대각선을 출력하는 방법은 무엇입니까?

예를 들어 다음과 같은 내용의 파일을 받았습니다.

1,2,3,4,5
6,7,8,9,0
1,2,3,4,5
6,7,8,9,0
1,2,3,4,5

출력은 다음과 같 1 7 3 9 5거나 이와 유사해야 합니다.

컷(cut -d "," -f5 파일 이름)을 통해 열을 출력할 수 있지만 대각선만 출력하려면 무엇을 써야 할지 모르겠습니다.

답변1

@don_chrissti의 솔루션만큼 우아하지는 않지만 awk 솔루션은 정사각형이 아닌 곳에서 작동합니다.

awk -F, '{a=a$++n" "}END{print a}' file

답변2

파이썬과 numpy

우리가 보고 있는 입력 데이터는 행렬 또는 2차원 배열로 볼 수 있습니다. 이제 이러한 관점에서 문제에 접근하면 행렬을 조작하는 데 사용할 수 있는 여러 계산 도구가 있음을 알 수 있습니다. 특히 Python의 numpy모듈에서는 이를 허용합니다. 따라서 우리는 함수 loadtxt()diagonal()필요한 데이터 추출이라는 두 가지를 사용할 수 있습니다 .

$ python -c 'import sys,numpy;a=numpy.loadtxt(sys.argv[1],dtype=int,delimiter=",");print( a.diagonal() )'  input.txt                                                                    
[1 7 3 9 5]

이제 대부분의 작업이 완료되었습니다. 출력을 좋게 만들기 위해 얻은 데이터를 문자열로 변환하고 해당 데이터에서 공백으로 구분된 문자열을 만듭니다. 이와 같이:

$ python -c 'import sys,numpy;a=numpy.loadtxt(sys.argv[1],delimiter=",");print(" ".join( [ str(int(i)) for i in a.diagonal() ]))'  input.txt                                            
1 7 3 9 5

물론 이 모든 것이 한 문장으로 이루어질 필요는 없습니다. 더 쉽게 읽을 수 있도록 명령줄에서 인수로 제공된 모든 파일 이름을 처리할 수 있는 작은 스크립트를 만들 수 있습니다.

#!/usr/bin/env python
import sys
import numpy as np

for filename in sys.argv[1:]:
    data=np.loadtxt(filename,delimiter=",")
    diag = data.diagonal()
    result_string = " ".join( [ str(int(i)) for i in diag ] ) 
    print(result_string)

답변3

sed -ne '
   y/,/\n/;G;s/\n$//

   y/\n_/_\n/;:loop
      /_$/{
         s///
         s/^[^_]*_//
         bloop
      }
   y/\n_/_\n/;P

   s/.*//;H
' input.file | paste -sd' '

공간을 보존하는 패턴 공간에서 건너뛰기를 위해 쉼표로 구분된 필드에 원장을 유지합니다.

루프는 양쪽 끝에서 패턴 공간을 잘라내어 가장 왼쪽이 인쇄하기에 익은 상황을 만듭니다. 우리는 이것을 양쪽 끝에서 양초를 태우는 것으로 상상할 수 있습니다(그러나 속도는 다릅니다). 앞에서는 쉼표로 구분된 필드를 잘라내고 끝에서는 후행 줄 바꿈이 \n더 이상 없을 때까지 굽기를 계속합니다.

이제 대각선 요소가 패턴 공간 앞에 있습니다.

이 아티팩트는 문자 클래스에서 개행 문자가 무효화되지 않는다는 y/\n_/_\n/사실을 해결하기 위한 것입니다 .POSIX sed[^\n]

현재 라인의 마지막 스텝으로 보유 영역이 증가됩니다. 이 paste명령은 한 줄에 출력을 가져옵니다.


CSV의 모든 필드가 숫자라고 가정하면 다음 코드 조각을 사용할 수도 있습니다 dc. trdc 필드는 공백으로 구분되고 음수는 - 대신 _로 시작하기 때문에 쉼표를 제거합니다 .

tr ',-' ' _' < file | dc -e '[q]sq [s0zlk<a]sa [?z0=qzlk1+dsk<an32ancz0=?]s? 0skl?x[]p'

q완료 시 종료하기 위한 3개의 매크로를 정의하고 , a끝에서 요소를 제거하기 위한 루프(팝)를 정의했으며, ?라인 지향 읽기를 수행하고 매크로를 호출한 다음 현재 노출된 진단 요소를 인쇄하도록 루프를 설정했습니다 a.

tr ... |
dc -e '
   # quit macro
   [q]sq

   # macro to pop elements from stack till they are more than counter k
   [s0 zlk<a]sa

   # do-while loop for reading lines
   [
      ?z0=q       # quit if line read is empty
      zlk1+dsk<a  # increment the counter k and compare it against NF (z) call a if >
      n 32an      # print the diagonal element and a space (no newlines)
      c z0=?      # invoke myself again 
   ]s?

   # main
   0sk  # initialize the counter k
   l?x  # call the macro ? to start the file read-in loop
   []p  # print a trailing newline
'

산출:

1 7 3 9 5

답변4

추상적인:

  1. 정사각형.....:awk -F, '{printf(NR==1?$NR:" "$NR)}END{printf("\n")}' file
  2. 직사각형:

    awk -F, ' NR==1{printf($1);next}
              {printf(" "$(NR>NF?NF:NR))}END{printf("\n")}
            ' file`
    
  3. 기타 대각선:

    awk -F, -vdiag=9 -vdir=-1 '
        {d=(NR-1)*(dir>0?1:-1)+1+diag;d=(d<1?1:d);d=(d>NF?NF:d)}
        {printf("%s%s",NR==1?"":" ",$d)}
        END {printf("\n")}
     ' file
    
  4. Posix는 대각선의 수와 방향을 선택합니다 /. \(코드가 더 깁니다. 기사 끝부분을 읽어보세요.)


세부 사항

지골

awk를 사용하는 가장 우아한 솔루션은 다음과 같습니다.

$  awk -F, '{print $NR}' file
1
7
3
9
5

한 줄의 출력을 얻으려면 다음을 수행할 수 있습니다(후행 공백).

$ awk -F, -v ORS=" " '{print $NR}' file; echo
1 7 3 9 5 

출력에 후행 공백이 없어야 하는 경우:

$  awk -F, '{printf(NR==1?$NR:" "$NR)}END{printf("\n")}' file
1 7 3 9 5

직사각형

예를 들어 다음 내용이 포함된 파일의 경우:

$ cat file
1,2,3,4,5
6,7,8,9,0
1,2,3,4,5
6,7,8,9,0
1,2,3,4,5
a,b,c,d,e
f,g,h,i,j
k,l,m,n,o
p,q,r,s,t
u,v,w,x,y

위의 솔루션은 공백을 인쇄합니다.

$ awk -F, '{printf(NR==1?$NR:" "$NR)}END{printf("|\n")}' file
1 7 3 9 5     |

이 경우 처리를 중지하려면 레코드 수가 필드 수보다 큰지 확인하는 것이 해결책일 수 있습니다(행당 필드 수가 변경되면 올바른 해결책이 아닐 수 있음).

$ awk -F, 'NR>NF{exit}{printf(NR==1?$NR:" "$NR)}END{printf("|\n")}' infile
1 7 3 9 5|

NR > NF인 행의 마지막 필드를 인쇄하려는 경우:

$ awk -F, 'NR==1{printf($1);next}{printf(" "$(NR>NF?NF:NR))}END{printf("|\n")}' file
1 7 3 9 5 e j o t y|

다른 대각선

필요한 것이 "주 대각선"과 다른 대각선인 경우 변수 diag를 0이 아닌 다른 값으로 설정하여 이를 나타낼 수 있습니다(이 코드에서는 0이 주 대각선입니다).

$ awk -F, -vdiag=3   '   {d=NR+diag;d=(d<1?1:d);d=(d>NF?NF:d)}
                         {printf("%s%s",NR==1?"":" ",$d)}
                         END {printf("\n")}
                     ' file
4 0 5 0 5 e j o t y

diag 값은 음수일 수 있습니다.

 $ awk -F, -vdiag=-3 '   {d=NR+diag;d=(d<1?1:d);d=(d>NF?NF:d)}
                         {printf("%s%s",NR==1?"":" ",$d)}
                         END {printf("\n")}
                     ' infile
 1 6 1 6 2 c i o t y

대각선은 수학적인 /표현과 유사할 수 있습니다 \.

$ awk -F, -vdiag=4 -vdir=-1 '
    {d=(NR-1)*(dir>0?1:-1)+1+diag;d=(d<1?1:d);d=(d>NF?NF:d)}
    {printf("%s%s",NR==1?"":" ",$d)}
    END {printf("\n")}
' file
5 9 3 7 1 a f k p u

$ awk -F, -vdiag=9 -vdir=-1 '
    {d=(NR-1)*(dir>0?1:-1)+1+diag;d=(d<1?1:d);d=(d>NF?NF:d)}
    {printf("%s%s",NR==1?"":" ",$d)}
    END {printf("\n")}
' infile
5 0 5 0 5 e i m q u

보스크껍데기

다른 입력 파일을 사용하십시오.

$ printf '%s\n' {1..6}{1..5} 7{1..3} | pr -ta -5 -s',' | tee inputfile
11,12,13,14,15
21,22,23,24,25
31,32,33,34,35
41,42,43,44,45
51,52,53,54,55
61,62,63,64,65
71,72,73

Posix 호환 쉘에서 awk에 해당하는 것은 다음과 같습니다:

diagPosix(){ diag=${1%%[!0-9+-]*} dir=$(((${2:-1}>0)?1:-1)) n=0 a=""
             while read x ; do
#                echo "testing $n $x"
                 IFS=',' eval 'set -- $x'  # Place values in pos parms.
                 a=$(( diag + n*dir    ))  # calculate position a
                 b=$(( (a<0)?0:a       ))  # low limit is zero (0)
                 d=$(( (b>$#-1)?$#-1:b ))  # upper limit is ($#-1)
#                echo "a=$a b=$b d=$d #=$# n=$n"
                 shift $d                  # remove leading parms
                 printf '%s' "$s" "$1"     # print parm (and an space)
                 s=" "                     # Next loop will have space.
                 n=$((n+1))                # In which line are we?
             done <"${3:-inputfile}"
             echo 
           }
diagPosix "$@"

위의 입력을 사용하면 다음과 같이 작동합니다.

$ ./script 0 1 inputfile
11 22 33 44 55 65 73

$ ./script -2 1 inputfile
11 21 31 42 53 64 73

$ ./script 4 -1 inputfile
15 24 33 42 51 61 71

코드는 일부 쉘에서 테스트되었으며 정상적으로 작동했습니다.

ash             : 11 22 33 44 55 65 73
/usr/bin/yash   : 11 22 33 44 55 65 73
y2sh            : 11 22 33 44 55 65 73
dash            : 11 22 33 44 55 65 73
zsh/sh          : 11 22 33 44 55 65 73
b203sh          : 11 22 33 44 55 65 73
b204sh          : 11 22 33 44 55 65 73
b205sh          : 11 22 33 44 55 65 73
b30sh           : 11 22 33 44 55 65 73
b32sh           : 11 22 33 44 55 65 73
b41sh           : 11 22 33 44 55 65 73
b42sh           : 11 22 33 44 55 65 73
b43sh           : 11 22 33 44 55 65 73
b44sh           : 11 22 33 44 55 65 73
lksh            : 11 22 33 44 55 65 73
mksh            : 11 22 33 44 55 65 73
ksh93           : 11 22 33 44 55 65 73
attsh           : 11 22 33 44 55 65 73
zsh/ksh         : 11 22 33 44 55 65 73

zsh는 기본적으로 분할되지 않고 배열 번호 지정이 1(0이 아님)에서 시작하기 때문에 zsh는 실패합니다(시뮬레이션에서는 아님). csh 및 tcsh에서 테스트했지만 작동하지 않습니다.
그것은아니요거기에서 작동할 것으로 예상됩니다(csh를 스크립트로 사용하지 마십시오!).

상향식으로 작동하는 솔루션은 입력에 tac을 사용하여 쉽게 구축할 수 있어야 합니다.

관련 정보