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


135

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

열 1 열 2
str1 1
str2 2
str3 3

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

cut -f2,1 file.txt

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

감사합니다.

답변:


148

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

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

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

awk대신 사용하십시오 :

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

12
cut이 직관적 재정렬 명령을 지원하지 않는 것은 너무 나쁩니다 . 어쨌든, 또 다른 팁 : 당신은 사용할 수 awk-FS-OFS사용 사용자 정의 입력하고 (같은 출력 필드 분리에 옵션을 -d--output-delimiter에 대한 cut).
말라 나

12
죄송합니다 FS. 옵션이며 OFS변수입니다. 예awk -v OFS=";" -F"\t" '{print $2,$1}'
말라 나

2
Git Bash의 Windows 사용자에 대한 참고 사항 : 위의 명령에서 이상한 결과가 발생하고 서로 재정의하는 열처럼 보이는 경우 캐리지 리턴이 원인입니다. 파일의 EOL을 CRLF에서 LF로 변경하십시오.
jakub.g

1
또는 입력 파일을 변경하지 않으려면 | sed 's/\r//' | 배관 전에awk
jakub.g로

2
이것은 매우 간단하지만 일부에게는 유용 할 수 있습니다. 탭으로 재정렬하기 위해 공간을 \ t로 awk '{print $4 "\t" $2 "\t" $6 "\t" $7}' file
바꾸면

64

또한 결합 할 수 cutpaste:

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

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

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

3
이것이 "영리하게"자격이 있는지 확실하지 않지만 f = file.txt paste <(cut -f2 $ f) <(cut -f1 $ f). 또한이 방법은 많은 열이 있고 큰 블록 주위를 이동하려는 경우 가장 쉽습니다.
Michael Rusch

같은 열에서 가변 길이의 셀에서는 작동하지 않습니다
kraymer

2
@kraymer 무슨 뜻인가요? cut고유 한 열 구분 기호가 있으면 가변 길이 열에 적합합니다.
tripleee

1
중복 파일을 제거하기 위해 아마도 tee를 사용할 수 있습니다.
JJW5432

2
다음을 수행하여 bashisms 를 피하고 하나의 인스턴스를 제거 할 수 있습니다 cut. paste file.txt file.txt | cut -f2,3
agc

7

껍질 만 사용해서

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

이것은 종종 비효율적입니다. 예를 들어 일반적으로 해당 Awk 스크립트가 훨씬 빠릅니다. 또한 값을 인용주의해야 "$col2"하고 "$col1"- 쉘 메타 문자 또는 데이터의 다른 헛소리있을 수 있습니다.
tripleee

7

이를 위해 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에서 훨씬 더 많은 계산을 수행 할 수 있다는 것입니다.


perlrun (1)은 -a를 암시 적으로 설정한다고 주장하지만 -n을 설정하지 않고 실행하면 반복되지 않습니다. 이상한.
Trenton

어떤 버전? 나를 위해 perl -ae print작동cat
pwes

5

사용 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

3

방금 비슷한 일을하고 있었지만 전문가는 아니지만 내가 사용한 명령을 공유한다고 생각했습니다. 다중 열 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

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


이것은 제기 된 질문에 대한 답변이 아닙니다. 스택 오버플로의 정신으로 게시하기 전에 문제를 해결할 시간을 보내십시오.
빌 게일

0

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입니다.

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


0

@Met의 답변을 확장하고 Perl도 사용
하십시오. 입력 및 출력이 TAB로 구분 된 경우 :

perl -F'\t' -lane 'print join "\t", @F[1, 0]' in_file

입력과 출력이 공백으로 구분 된 경우 :

perl -lane 'print join " ", @F[1, 0]' in_file

여기서는
-e별도의 스크립트 파일이 아닌 코드 인라인을 찾고 Perl에게
-n한 번에 한 줄씩
-l입력 \n을 읽고, 줄을 읽은 후 ( * NIX에서) 입력 레코드 구분 기호를 제거하고 chomp출력을 추가 하도록 지시 합니다. (기록 세퍼레이터 \n각각에 NIX *)는 print,
-a어레이에 공백의 입력 라인을 분리 @F,
-F'\t'조합하여 -a스플릿 배열에 입력 탭 선 대신 공백 @F.

@F[1, 0]는 배열의 두 번째 및 첫 번째 요소로 구성된 배열 @F입니다. Perl의 배열은 인덱스가 0이고, 필드 cut는 1 인덱스입니다. 에있는 필드 @F[0, 1]는의 필드와 동일한 필드입니다 cut -f1,2.

이러한 표기법은 위에 게시 된 다른 답변보다 간단한 입력 조작을 가능하게합니다 (간단한 작업에는 적합합니다). 예를 들면 다음과 같습니다.

# reverses the order of fields:
perl -F'\t' -lane 'print join "\t", reverse @F' in_file

# prints last and first fields only:
perl -F'\t' -lane 'print join "\t", @F[-1, 0]' in_file
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.