sed
and를 사용하는 것보다 여러 값 열을 얻는 더 빠른 방법이 있습니까 awk
?
예를 들어, 출력이 있고 ls -hal /
파일 및 디렉터리 이름과 크기만 가져오려는 경우 어떻게 해야 합니까?용이하게그리고빠르게명령을 수정하는 데 몇 분을 소비하지 않고도 이 작업을 수행할 수 있습니다.
total 16078
drwxr-xr-x 33 root wheel 1.2K Aug 13 16:57 .
drwxr-xr-x 33 root wheel 1.2K Aug 13 16:57 ..
-rw-rw-r-- 1 root admin 15K Aug 14 00:41 .DS_Store
d--x--x--x 8 root wheel 272B Jun 20 16:40 .DocumentRevisions-V100
drwxr-xr-x+ 3 root wheel 102B Mar 27 12:26 .MobileBackups
drwx------ 5 root wheel 170B Jun 20 15:56 .Spotlight-V100
d-wx-wx-wt 2 root wheel 68B Mar 27 12:26 .Trashes
drwxrwxrwx 4 root wheel 136B Mar 30 20:00 .bzvol
srwxrwxrwx 1 root wheel 0B Aug 13 16:57 .dbfseventsd
---------- 1 root admin 0B Aug 16 2012 .file
drwx------ 1275 root wheel 42K Aug 14 00:05 .fseventsd
drwxr-xr-x@ 2 root wheel 68B Jun 20 2012 .vol
drwxrwxr-x+ 289 root admin 9.6K Aug 13 10:29 Applications
drwxrwxr-x 7 root admin 238B Mar 5 20:47 Developer
drwxr-xr-x+ 69 root wheel 2.3K Aug 12 21:36 Library
drwxr-xr-x@ 2 root wheel 68B Aug 16 2012 Network
drwxr-xr-x+ 4 root wheel 136B Mar 27 12:17 System
drwxr-xr-x 6 root admin 204B Mar 27 12:22 Users
drwxrwxrwt@ 6 root admin 204B Aug 13 23:57 Volumes
drwxr-xr-x@ 39 root wheel 1.3K Jun 20 15:54 bin
drwxrwxr-t@ 2 root admin 68B Aug 16 2012 cores
dr-xr-xr-x 3 root wheel 4.8K Jul 6 13:08 dev
lrwxr-xr-x@ 1 root wheel 11B Mar 27 12:09 etc -> private/etc
dr-xr-xr-x 2 root wheel 1B Aug 12 21:41 home
-rw-r--r--@ 1 root wheel 7.8M May 1 20:57 mach_kernel
dr-xr-xr-x 2 root wheel 1B Aug 12 21:41 net
drwxr-xr-x@ 6 root wheel 204B Mar 27 12:22 private
drwxr-xr-x@ 68 root wheel 2.3K Jun 20 15:54 sbin
lrwxr-xr-x@ 1 root wheel 11B Mar 27 12:09 tmp -> private/tmp
drwxr-xr-x@ 13 root wheel 442B Mar 29 23:32 usr
lrwxr-xr-x@ 1 root wheel 11B Mar 27 12:09 var -> private/var
ls
나는 내가 할 수 있는 선택지가 셀 수 없이 많다는 것을 깨달았다.이 특별한 예의 경우그러나 이것은 일반적인 문제이며 특정 열을 쉽고 빠르게 얻을 수 있는 일반적인 솔루션을 원합니다.
cut
정규식이 필요하지 않고 열이 단일 공백으로 구분되는 상황이 거의 발생하지 않으므로 잘라내지 않겠습니다. 작동한다면 완벽할 것입니다.
ls -hal / | cut -d'\s' -f5,9
awk
그리고 sed
내가 원하는 것보다 더 일반적입니다. 기본적으로 전체 언어 자체입니다. 나는 그들에게 반대할 생각이 없습니다. 단지 제가 최근에 그들과 많은 일을 하지 않은 이상, 그들의 방식으로 생각하고 유용한 글을 쓰기 시작하려면 상당한 정신적 변화가 필요하다는 것뿐입니다. 나는 보통 해결하려는 다른 문제에 대해 생각하고 있는데, 갑자기 하나 sed
/ awk
문제를 해결해야 하면 주의가 산만해집니다.
내가 원하는 것을 달성할 수 있는 유연한 지름길이 있습니까?
답변1
왜인지는 모르겠지만
ls -hal / | awk '{print $5, $9}'
귀하의 의견으로는 이것이 귀하의 사고 과정에 더 파괴적인 것보다
ls -hal / | cut -d'\s' -f5,9
효과가 있었다면 그랬을 것입니다. 꼭 적어야 하나요? 몇 줄만 awk
자동으로 추가됩니다. {}
(저에게 가장 어려운 문제는 어떤 필드 번호가 어떤 데이터에 해당하는지 기억하는 것입니다. 하지만 여러분에게는 그런 문제가 없을 수도 있습니다.)
당신은 사용할 필요가 없습니다모두awk의 기능: 단순히 특정 열을 출력하려면 awk에 대해 거의 알아야 합니다.
성가신 문제는 파일 이름과 함께 심볼릭 링크를 출력하려는 경우 또는 파일 이름에 공백이 있을 수 있다는 것입니다. (또는 더 나쁘게는 개행 문자). 가정된 정규식 인식 클리핑을 사용하면 문제가 되지 않습니다(개행 제외) -f5,9
. -f5,9-
그러나 "필드 9에서 끝까지"에는 awk 구문이 없으므로 for 루프를 작성하는 방법을 기억해야 합니다. .
cut
이것은 -style -f
옵션을 awk 프로그램으로 변환한 다음 awk 프로그램을 실행하는 작은 쉘 스크립트입니다 . 더 나은 오류 검사가 필요하지만 작동하는 것 같습니다. (보너스: -d
옵션은 awk 프로그램에 전달하여 처리됩니다.)
#!/bin/bash
prog=\{
while getopts f:d: opt; do
case $opt in
f) IFS=, read -ra fields <<<"$OPTARG"
for field in "${fields[@]}"; do
case $field in
*-*) low=${field%-*}; high=${field#*-}
if [[ -z $low ]]; then low=1; fi
if [[ -z $high ]]; then high=NF; fi
;;
"") ;;
*) low=$field; high=$field ;;
esac
if [[ $low == $high ]]; then
prog+='printf "%s ", $'$low';'
else
prog+='for (i='$low';i<='$high';++i) printf "%s ", $i;'
fi
done
prog+='printf "\n"}'
;;
d) sep="-F$OPTARG";;
*) exit 1;;
esac
done
if [[ -n $sep ]]; then
awk "$sep" "$prog"
else
awk "$prog"
fi
빠른 테스트:
$ ls -hal / | ./cut.sh -f5,9-
7.0K bin
5.0K boot
4.2K dev
9.0K etc
1.0K home
8.0K host
33 initrd.img -> /boot/initrd.img-3.2.0-51-generic
33 initrd.img.old -> /boot/initrd.img-3.2.0-49-generic
...
답변2
나는 sed나 awk보다 더 간단한 해결책은 없다고 생각합니다. 하지만 자신만의 함수를 작성할 수 있습니다.
목록 기능은 다음과 같습니다(터미널에 복사하여 붙여넣기).
function list() { ls -hal $1 | awk '{printf "%-10s%-30s\n", $5, $9}'; }
그런 다음 목록 기능을 사용하십시오.
list /
list /etc
답변3
열이 무엇인지 설명하지 않고 "열"에 대해서만 이야기할 수는 없습니다!
Unix 텍스트 처리에서는 공백을 열(필드) 구분 기호로 사용하고 (자연) 개행 문자를 행 또는 레코드 구분 기호로 사용하는 것이 매우 일반적입니다. 다음 awk
은 읽기 쉬운 훌륭한 도구입니다.
# for words (columns) 5 and 9:
ls -lah | awk '{print $5 " " $9}'
# or this, for the fifth and the last word:
ls -lah | awk '{print $5 " " $NF}'
열을 문자별로 정렬하면 더 좋을 것 같습니다 cut -c
.
ls -lah | cut -c 31-33,46-
awk
이 옵션을 사용하면 다른 필드 구분 기호를 사용할 수 있습니다 -F
. 와 함께 -c
(또는 -b
)을 사용 하지 않는 경우 를 cut
사용하여 -f
출력할 열을 지정합니다.
비결은 입력을 이해하는 것입니다.
ls
일반적으로 텍스트 처리 도구를 사용하여 , 및 유사한 도구의 출력을 구문 분석하는 것이 항상 좋은 생각은 아닙니다. 적어도 이식성/호환성을 원하는 경우에는 그렇지 않습니다 df
. ps
이러한 경우 POSIX 정의 형식으로 출력을 강제 실행해 보십시오. 때로는 -P
출력을 생성하는 명령에 일부 옵션(아마도)을 전달하여 이를 달성할 수 있습니다. 때로는 환경 변수(예:)를 설정하거나 POSIXLY_CORRECT
특정 바이너리(예: /usr/xpg4/bin/ls
.
답변4
이에 대해 아무도 글을 쓰지 않은 것이 놀랍지만, cut
반복되는 공백을 단일 구분 기호로 처리하지 않는다는 점이 유일한 반대라면, 반복되는 공백을 그냥 짜내는 것은 어떻습니까? 이것은 그 용도 중 하나입니다 tr
.
ls -l | tr -s ' ' | cut -d ' ' -f5,9
귀하의 질문에 표시된 출력을 고려하면 ls -l
결과는 다음과 같습니다.
1.2K .
1.2K ..
15K .DS_Store
272B .DocumentRevisions-V100
102B .MobileBackups
170B .Spotlight-V100
68B .Trashes
136B .bzvol
0B .dbfseventsd
0B .file
42K .fseventsd
68B .vol
9.6K Applications
238B Developer
2.3K Library
68B Network
136B System
204B Users
204B Volumes
1.3K bin
68B cores
4.8K dev
11B etc
1B home
7.8M mach_kernel
1B net
204B private
2.3K sbin
11B tmp
442B usr
11B var