첫 줄 들여쓰기를 기반으로 여러 줄의 선행 공백을 제거하는 방법은 무엇입니까?

첫 줄 들여쓰기를 기반으로 여러 줄의 선행 공백을 제거하는 방법은 무엇입니까?

텍스트를 한 줄씩 처리하고 각 줄에서 선행 공백을 제거하는 것은 쉽습니다.

$ LC_ALL=C git ls-files | sed -nE 's:^.*(\.[^./]+)$:\1:p' \
    | sort | uniq -c | sort -snr > lines # create example "lines" file
$ cat lines # "lines" example file
     30 .md
      8 .png
      4 .yml
      1 .css
      1 .gitignore
      1 .ico
      1 .sh
      1 .txt
$ sed -Ee 's/^ +//' lines # removing leading spaces (U+0020)
30 .md
8 .png
4 .yml
1 .css
1 .gitignore
1 .ico
1 .sh
1 .txt

그러나 모든 후속 행을 제거하기 위해 첫 번째 행에서만 공백 수를 설정해야 하는 경우 이를 달성하는 방법은 무엇입니까? 출력은 다음과 같습니다.

30 .md
 8 .png
 4 .yml
 1 .css
 1 .gitignore
 1 .ico
 1 .sh
 1 .txt

내가 달성하고 싶은 것은 그것을 파이프로 연결하는 것입니다.칼럼(1)출력을 더 조밀하게 만들지 만 모든 라인에서 수평 간격을 유지합니다. 시뮬레이션:

$ column -x lines | expand -t 8
     30 .md                   8 .png                  4 .yml
      1 .css                  1 .gitignore            1 .ico
      1 .sh                   1 .txt

이제는 왼쪽 부분이 잘리지 않고 공간을 많이 활용하게 되었습니다.독특한(1)그리고-씨오른쪽 정렬 숫자(위치 8)로 추가하는 옵션입니다.

최대 개수가 고정되어 있다고 가정하는 한(예: 최대 길이가 두 자리) 하드코딩할 수 있습니다.

sed -Ee 's/^ {5}//' lines | column -x | expand -t 8
30 .md           8 .png          4 .yml          1 .css          1 .gitignore
 1 .ico          1 .sh           1 .txt

답변1

Gnu sed: 선행 공백을 유지에 저장한 다음 각 줄에서 이 만큼의 선행 공백을 제거합니다. 행이 표시된 대로 정렬되어 있다고 가정합니다.

sed -Ee '
  1{h;s/\S.*//;x;}
  G;s/^(\s*)(.*)\n\1$/\2/
' file

awk '
NR==1 {
  l0=length()
  $1=$1
  re = "^\\s{" l0-length() "}"
}
sub(re, "")+1
' file

perl -lpe '
  $x //= do{/^\s*/g;+pos;};
  $_ = substr($_,$x);
' file

답변2

조사를 했어야 했는데어크(1)더 일찍. 최소한 첫 번째 줄의 선행 공백 수를 저장하고 각 줄의 형식을 지정하는 작은 프로그램을 작성할 수 있습니다.

$ awk '
    NR==1 && match($0, /^ */) {p=RLENGTH+1};
    {print(substr($0,p))}
' lines | column -x | expand -t 8
30 .md           8 .png          4 .yml          1 .css          1 .gitignore
 1 .ico          1 .sh           1 .txt

답변3

왜 첫 번째 줄로 제한합니까? 기가바이트 단위의 데이터를 처리할 필요가 없다면(모든 데이터를 메모리에 저장하는 것은 문제가 됩니다) 가장 긴 첫 번째 필드를 저장하고 이를 사용하여 나머지의 형식을 지정할 수 있습니다.

$ cat lines 
      4 .yml
      1 .sh
      1 .ico
      1 .gitignore
      1 .css
     30 .md
      1 .txt
      8 .png

그리고:

$ awk -v l=0 '{ 
                if(length($1)>l){
                    l=length($1)
                } 
                a[$2]=$1
              }
              END{
                for(line in a){
                    printf "%"l"s %s\n",a[line],line
                }
             }' lines 
 8 .png
 1 .ico
 1 .txt
 1 .css
 1 .sh
30 .md
 1 .gitignore
 4 .yml

그래서:

$ awk -v l=0 '{ if(length($1)>l){l=length($1)} a[$2]=$1}END{for(line in a){printf "%"l"s %s\n",a[line],line}}' lines | 
    column -x | expand -t 8
 8 .png          1 .ico          1 .txt          1 .css          1 .sh
30 .md           1 .gitignore    4 .yml

이것이 필요하지 않고 첫 번째 줄에만 관심이 있다면 다음과 같이 단순화할 수 있습니다.

$ perl -pe '/^(\s+)/; $l//=$1; s/^$l//' lines | column -x | expand -t 8
30 .md           4 .yml          1 .sh           1 .ico          1 .gitignore
 1 .css          1 .txt          8 .png

답변4

내가 이해하고 올바른 길을 가고 있기를 바랍니다.

$ sed 's/^[[:blank:]]//' file | cut -d' ' -f3- | column -x | expand -t 8 | cut -d' ' -f3-
30 .md           8 .png          4 .yml          1 .css          1 .gitignore
 1 .ico          1 .sh           1 .txt

이러한 시나리오의 경우 예를 들면 다음과 같습니다.

     30 .md
      8 .png
      4 .yml
      1 .css
      1 .gitignore
   4000 .ico
      1 .sh
      1 .txt
    300 .foo
$ sed 's/^[[:blank:]]//' file | cut -d' ' -f3- | column -x | expand -t 8 | cut -d' ' -f3-
30 .md           8 .png          4 .yml          1 .css       4000 .ico      
 1 .gitignore    1 .sh           1 .txt        300 .foo

관련 정보