[shell] 잘라내기를 사용하여 열 재정렬

다음 형식의 파일이 있습니다

열 1 열 2
str1 1
str2 2
str3 3

열을 다시 정렬하고 싶습니다. 나는 아래 명령을 시도했다

cut -f2,1 file.txt

이 명령은 열 순서를 바꾸지 않습니다. 왜 작동하지 않는지 아십니까?

감사합니다.



답변

에 대한 cut(1)매뉴얼 페이지

-b, -c 또는 -f 중 하나만 사용하십시오. 각 LIST는 하나의 범위 또는 쉼표로 구분 된 많은 범위로 구성됩니다. 선택된 입력은 읽은 순서와 동일한 순서로 작성되며 정확히 한 번만 기록됩니다.

먼저 필드 1에 도달하여 인쇄되고 필드 2가옵니다.

awk대신 사용하십시오 :

awk '{ print $2 " " $1}' file.txt


답변

또한 결합 할 수 cutpaste:

paste <(cut -f2 file.txt) <(cut -f1 file.txt)

주석을 통해 : bashisms을 피하고 다음을 수행하여 컷 인스턴스를 제거 할 수 있습니다.

paste file.txt file.txt | cut -f2,3


답변

껍질 만 사용해서

while read -r col1 col2
do
  echo $col2 $col1
done <"file"


답변

이를 위해 Perl을 사용할 수 있습니다.

perl -ane 'print "$F[1] $F[0]\n"' < file.txt
  • -e 옵션은 명령을 실행 한 후
  • -n은 한 줄씩 읽음을 의미합니다 (이 경우 STDOUT 파일을 열고 행을 반복합니다).
  • -a는 이러한 행을 @F ( “F”-Field와 같은)라는 벡터로 분할하는 것을 의미합니다. Perl은 1부터 시작하는 필드를 색인화하는 cut과 달리 0에서 시작하는 벡터를 색인화합니다.
  • 기본 공백 대신 파일을 읽을 때 패턴 을 필드 구분 기호로 사용하기 위해 -F 패턴 (-F와 pattern 사이에 공백이 없음)을 추가 할 수 있습니다.

펄 실행의 장점은 (펄을 알고 있다면) 열을 다시 정렬하는 것보다 F에서 훨씬 더 많은 계산을 수행 할 수 있다는 것입니다.


답변

사용 join:

join -t $'\t' -o 1.2,1.1 file.txt file.txt

노트:

  • -t $'\t'에서 GNU join 더 직관적이 -t '\t' 없이 (가) $실패, ( 로 coreutils는 v8.28 이전?); 아마도 해결 방법 $이 필요한 버그 일 것입니다 . 유닉스 조인 구분자 char 참조 .

  • join하나의 파일 만 작업 중이지만 두 개의 파일 이름이 필요합니다. 같은 이름을 두 번 사용하여 속임수join 원하는 작업을 수행 할 수 있습니다.

  • 리소스가 적은 시스템 join의 경우 다른 답변에 사용 된 일부 도구보다 설치 공간이 작습니다.

    wc -c $(realpath `which cut join sed awk perl`) | head -n -1
      43224 /usr/bin/cut
      47320 /usr/bin/join
     109840 /bin/sed
     658072 /usr/bin/gawk
    2093624 /usr/bin/perl

답변

방금 비슷한 일을하고 있었지만 전문가는 아니지만 내가 사용한 명령을 공유한다고 생각했습니다. 다중 열 csv가 있었는데 4 열만 필요했고 다시 정렬해야했습니다.

내 파일은 파이프 ‘|’ 구분되지만 교환 할 수 있습니다.

LC_ALL=C cut -d$'|' -f1,2,3,8,10 ./file/location.txt | sed -E "s/(.*)\|(.*)\|(.*)\|(.*)\|(.*)/\3\|\5\|\1\|\2\|\4/" > ./newcsv.csv

틀림없이 그것은 정말로 거칠고 준비가되어 있지만, 그에 맞게 조정할 수 있습니다!


답변

sed 사용

기본 정규식의 중첩 된 하위 표현식과 함께 sed를 사용하여 열 컨텐츠를 캡처하고 순서를 변경하십시오. 이 방법은이 경우와 같이 열 순서를 변경하기 위해 컷 수가 제한되어있을 때 가장 적합합니다.

기본 아이디어는 \(및로 검색 패턴의 흥미로운 부분을 둘러싸 \)는 것입니다 \#.# 검색 패턴의 표현식의 순차적 위치를 나타낸다.

예를 들면 다음과 같습니다.

$ echo "foo bar" | sed "s/\(foo\) \(bar\)/\2 \1/"

수율 :

bar foo

하위 표현식 외부의 텍스트는 스캔되지만 대체 문자열에서 재생할 수 있도록 유지되지 않습니다.

이 질문은 고정 너비 열에 대해서는 다루지 않았지만 여기서는 해결 된 솔루션의 가치있는 척도이므로 여기서 논의 할 것입니다. 간단하게하기 위해 파일을 공간 구분 된 것으로 가정하지만 솔루션을 다른 구분 기호로 확장 할 수 있습니다.

접는 공간

가장 간단한 사용법을 설명하기 위해 여러 공백을 단일 공백으로 축소 할 수 있고 두 번째 열 값이 공백으로 채워지지 않은 EOL로 종료된다고 가정합니다.

파일:

bash-3.2$ cat f
Column1    Column2
str1       1
str2       2
str3       3
bash-3.2$ od -a f
0000000    C   o   l   u   m   n   1  sp  sp  sp  sp   C   o   l   u   m
0000020    n   2  nl   s   t   r   1  sp  sp  sp  sp  sp  sp  sp   1  nl
0000040    s   t   r   2  sp  sp  sp  sp  sp  sp  sp   2  nl   s   t   r
0000060    3  sp  sp  sp  sp  sp  sp  sp   3  nl
0000072

변환:

bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f | od -a
0000000    C   o   l   u   m   n   2  sp   C   o   l   u   m   n   1  nl
0000020    1  sp   s   t   r   1  nl   2  sp   s   t   r   2  nl   3  sp
0000040    s   t   r   3  nl
0000045

열 너비 유지

너비가 다른 열을 허용하면서 너비가 일정한 열이있는 파일로 메서드를 확장 해 보겠습니다.

파일:

bash-3.2$ cat f2
Column1    Column2
str1       1
str2       2
str3       3
bash-3.2$ od -a f2
0000000    C   o   l   u   m   n   1  sp  sp  sp  sp   C   o   l   u   m
0000020    n   2  nl   s   t   r   1  sp  sp  sp  sp  sp  sp  sp   1  sp
0000040   sp  sp  sp  sp  sp  nl   s   t   r   2  sp  sp  sp  sp  sp  sp
0000060   sp   2  sp  sp  sp  sp  sp  sp  nl   s   t   r   3  sp  sp  sp
0000100   sp  sp  sp  sp   3  sp  sp  sp  sp  sp  sp  nl
0000114

변환:

bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2
Column2 Column1
1       str1
2       str2
3       str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2 | od -a
0000000    C   o   l   u   m   n   2  sp   C   o   l   u   m   n   1  sp
0000020   sp  sp  nl   1  sp  sp  sp  sp  sp  sp  sp   s   t   r   1  sp
0000040   sp  sp  sp  sp  sp  nl   2  sp  sp  sp  sp  sp  sp  sp   s   t
0000060    r   2  sp  sp  sp  sp  sp  sp  nl   3  sp  sp  sp  sp  sp  sp
0000100   sp   s   t   r   3  sp  sp  sp  sp  sp  sp  nl
0000114

마지막으로 질문 예제에 길이가 다른 문자열이 없지만이 sed 표현식은이 경우를 지원합니다.

파일:

bash-3.2$ cat f3
Column1    Column2
str1       1
string2    2
str3       3      

변환:

bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3
Column2 Column1
1       str1
2       string2
3       str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3 | od -a
0000000    C   o   l   u   m   n   2  sp   C   o   l   u   m   n   1  sp
0000020   sp  sp  nl   1  sp  sp  sp  sp  sp  sp  sp   s   t   r   1  sp
0000040   sp  sp  sp  sp  sp  nl   2  sp  sp  sp  sp  sp  sp  sp   s   t
0000060    r   i   n   g   2  sp  sp  sp  nl   3  sp  sp  sp  sp  sp  sp
0000100   sp   s   t   r   3  sp  sp  sp  sp  sp  sp  nl
0000114

쉘에서 다른 열 순서 변경 방법과 비교

  • 놀랍게도 파일 조작 도구의 경우 awk는 필드에서 레코드 끝까지 자르기에 적합하지 않습니다. sed에서는 정규 표현식을 사용하여이를 수행 할 수 있습니다. 예를 들어 , 표현식이 열과 일치하는 \(xxx.*$\)위치 xxx입니다.

  • 쉘 스크립트 내부에서 구현할 때는 붙여 넣기 및 잘라 내기 서브 쉘을 사용하는 것이 까다로워집니다. 셸 스크립트로 가져올 때 명령 줄에서 작동하는 코드를 구문 분석하지 못합니다. 적어도 이것은 나의 경험이었습니다 (이 접근법으로 나를 이끌어 냈습니다).