다음과 같은 특정 텍스트가 포함된 열을 삭제하는 옵션을 찾고 있습니다.
"디디"
aaa bbb ccc ddd eee fff
1 2 3 4 5 6
2 3 4 5 6 0
따라서 출력은 다음과 같습니다.
aaa bbb ccc eee fff
1 2 3 5 6
2 3 4 6 0
열 4를 제거하고 동일한 작업을 수행하는 간단한 옵션이 있다는 것을 알고 있지만 내 *.csv 파일은 정렬되지 않습니다. 어떤 아이디어가 있나요?
답변1
sed
올바른 도구가 아닙니다. 노력하다 awk
:
$ awk -v OFS='\t' 'NR==1{for (i=1;i<=NF;i++)if ($i=="ddd"){n=i-1;m=NF-(i==NF)}} {for(i=1;i<=NF;i+=1+(i==n))printf "%s%s",$i,i==m?ORS:OFS}' file
aaa bbb ccc eee fff
1 2 3 5 6
2 3 4 6 0
삭제하려는 문자열( ddd
이 예에서는)이 첫 번째 행의 필드로 나타난다고 가정합니다.
어떻게 작동하나요?
-v OFS='\t'
그러면 출력 필드 구분 기호가 탭으로 설정됩니다. 다른 것을 사용하는 경우 이 설정을 변경하세요.
NR==1{for (i=1;i<=NF;i++)if ($i=="ddd"){n=i-1;m=NF-(i==NF)}}
그러면 첫 번째 행의 모든 열이 검색됩니다. (마이너스 1)로 열 번호를
ddd
변수에 저장합니다n
.m
마지막 열의 번호로 도 설정되는데 ,i
마지막 열인 경우 로 설정됩니다NF-1
.for(i=1;i<=NF;i+=1+(i==n))printf "%s%s",$i,i==m?ORS:OFS
ddd
그러면 첫 번째 줄에 나타나는 필드를 건너뛰고 모든 필드가 인쇄됩니다.i+=1
i
루프를 통과할 때마다 1씩 증가됩니다. 각 루프에서 1i+=1+(i==n)
씩 증가합니다i
. 단,i==n
이 경우에는i
2씩 증가합니다. 이는 오른쪽 열을 건너뛰는 효과가 있습니다.printf "%s%s",$i,i==m?ORS:OFS
마지막 열인지 여부에 따라i
열 구분 기호OFS
또는 행 구분 기호가 뒤에 오는 열을 인쇄합니다 .ORS
i
여러 줄
이와 같은 명령을 여러 줄로 작성하는 것을 선호하는 사람들을 위해:
awk -v OFS='\t' '
NR==1{
for (i=1;i<=NF;i++)
if ($i=="ddd") {
n=i-1
m=NF-(i==NF)
}
}
{
for(i=1;i<=NF;i+=1+(i==n))
printf "%s%s",$i,i==m?ORS:OFS
}
' file
쉼표로 구분된 파일 사용
입력과 출력을 쉼표로 구분하려면 입력 필드 구분 기호( 사용 -F
)와 출력 필드 구분 기호를 변경해야 합니다. 예를 들어 다음 입력 파일을 고려해보세요.
$ cat file2
aaa,bbb,ccc,ddd,eee,fff
1,2,3,4,5,6
2,3,4,5,6,0
그런 다음 다음을 사용하십시오.
$ awk -F, -v OFS=, 'NR==1{for (i=1;i<=NF;i++)if ($i=="ddd"){n=i-1;m=NF-(i==NF)}} {for(i=1;i<=NF;i+=1+(i==n))printf "%s%s",$i,i==m?ORS:OFS}' file2
aaa,bbb,ccc,eee,fff
1,2,3,5,6
2,3,4,6,0
답변2
이것은 (대부분의 경우)에서 가능할 수도 있지만 sed
다른 도구를 사용하는 것보다 더 간단할지는 의문입니다. 가장 쉬운 방법은 먼저 원하는 필드 번호를 얻은 다음 파일을 통해 나머지를 인쇄하는 것입니다. 예를 들어 Perl에서는 다음과 같습니다.
$ perl -lane 'if($.==1){for(0..$#F){$d=$_ if $F[$_] eq "ddd"}}
print "@F[0..$d-1] @F[$d+1..$#F]"' file
aaa bbb ccc eee fff
1 2 3 5 6
2 3 4 6 0
그러나 이로 인해 형식이 엉망이 됩니다. 중요하다면John1024의 답변 사용대신에.
답변3
#!/bin/bash
read -a header <file # read first line into array "header"
for i in ${!header[@]} # iterate through array indexes
do
if [ "${header[i]}" = "ddd" ] # find column equal the pattern
then
n=$[++i] # put column number in variable "n"
break
fi
done
# print all column except found delimited by <TAB>
cut --complement -f ${n} < <(tr -s ' ' '\t' <6)
하지만 원한다면 "그냥sed"(최적은 아니더라도)
sed "s/\S\+\s*//$(sed 's/\s\+/\n/g;1q' file | sed -n '/ddd/=')" file
\S\+\s*
- 평균 1개 열(공백이 아닌 문자 뒤에 가능한 공백이 있음).
s/<pattern>//<number>
- 교체만 가능숫자처음으로 나타남무늬. - 첫 번째 줄(제목)에서만
s/\s\+/\n/g
모든 공백 또는 공백 블록을 ewline으로 바꿉니다 . 따라서 헤더 열을 행으로 변환합니다. - 줄 번호를 출력하세요.\n
1q
sed -n '/ddd/=
무늬존재함 == 열 수
답변4
awk -F "\t" -v "Pat=ddd" 'NR == 1 {for( i = 1; i <= NF; i++) Take[ i] = (Pat != $i)} {for ( i = 1; i <= NF; i++) if( Take[ i]) printf $i FS; print ""}' YourFile
- 제외되지 않은 필드 인쇄
- 입력과 동일한 구분 기호를 사용하십시오(
-F "\t"
). - ( )를 제외하려면 패턴 선택에 변수를 사용하십시오
-v "Pat=ddd"
. 많은 선택을 하고 싶다면 정규식 선택을 쉽게 수정할 수 있습니다. - 혼란을 피하기 위해 2개의 루프로 완료되지만 하나의 루프에서만 수행됩니다.