때때로 다음과 같은 ls 출력 형식의 파일을 얻습니다.
/etc/cron.d:
-rw-r--r-- 1 root root 128 May 15 2020 0hourly
-rw------- 1 root root 235 Dec 17 2020 sysstat
/etc/cron.daily:
-rw------- 1 root root 235 Dec 17 2020 sysstat
일반 Gnu 도구를 사용하거나 bash 내부를 삭제하여 이를 조작할 수 있는 기회가 있습니까?
-rw-r--r-- 1 root root 128 May 15 2020 /etc/cron.d/0hourly
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.d/sysstat
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.daily/sysstat
훌륭해요.
가장 쉬운 방법은 다음과 같이 파일 경로를 제거하는 것입니다.
cat <filename> | grep -v -E "^\/[a-z]"
하지만 제가 말했듯이 이 경로를 파일 이름이 있는 후속 줄로 어떻게 이동할 수 있습니까?
주어진 명령은 다음과 같습니다: ls -lR /etc/cron* > <filename>
.
나는 해당 출력에 영향을 미치지 않지만 ls에 의해 실행된 이러한 명령의 출력을 <filename>
나에게 전송되는 별도의 파일로 리디렉션합니다.
내가 하고 싶은 것은 그 내용을 언급된 두 번째 결과로 조작하는 것입니다. 기본적으로 첫 번째 줄을 가져와서 파일의 2번째와 3번째 줄에 경로를 적용한 다음, 4번째 줄을 가져와 5번째 줄에 적용합니다. 그런 다음 이를 일반 방법으로 구성합니다.
awk를 사용하면 효과가 있을 것 같아요.
답변1
파일 이름이나 디렉터리 이름에 공백이 없으면 POSIX awk를 사용하여 다음을 수행할 수 있습니다.
$ awk '
NF==1 && sub(/:$/,"/") { dir=$0; next }
match($0,/[^[:space:]]+$/) { $0=substr($0,1,RSTART-1) dir substr($0,RSTART) }
{ print }
' file
-rw-r--r-- 1 root root 128 May 15 2020 /etc/cron.d/0hourly
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.d/sysstat
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.daily/sysstat
또는 파일/디렉터리 이름에 공백이 포함될 수 있지만 디렉터리 경로가 항상 다음으로 시작 /
하고 ls
출력에 항상 파일 이름 앞에 정확히 동일한 수의 필드가 있는 경우(예제에서와 같이) 다음을 수행할 수 있습니다.
$ awk '
/^\// && sub(/:$/,"/") { dir=$0; next }
match($0,/^([^[:space:]]+[[:space:]]+){8}/) { $0=substr($0,1,RLENGTH) dir substr($0,RLENGTH+1) }
{ print }
' file
그러나 ls
이러한 필드를 사용하여 출력을 생성하는 것이 항상 가능한 것은 아니며( ls
날짜/시간 출력은 파일의 수명과 로캘에 따라 다르며 예를 들어 사용자 ID에는 공백이 포함될 수 있음) 각 파일 줄의 모든 문자가 나타날 수 있습니다. 파일 및 디렉터리 이름에는 :
YMMV를 제외한 모든 문자가 포함될 수 있으므로 디렉터리 이름은 사용자가 생각하는 /
대로 끝날 수 있습니다. NUL
줄을 구별한 다음 각 파일 줄에서 파일 이름을 찾아보세요. 또한 파일 이름에 개행 문자가 포함될 수 있는데 이는 완전히 또 다른 문제입니다.
ls
따라서 생성할 수 있는 모든 가능한 출력을 구문 분석하는 신뢰할 수 있는 방법은 없습니다 . 이 작업을 수행하려면 호출하는 컨텍스트에 관계없이 충분하다고 생각하거나 원하는 패턴 일치가 무엇인지 파악한 ls
다음 이를 기반으로 스크립트를 작성하면 됩니다.
일부 다른 도구는 ls
구문 분석해야 하는 출력 파일을 생성하므로 구문 분석을 시도하면 안 된다는 것을 우리 모두 알고 있으므로 다른 도구를 수정해야 합니다 ls
(참조http://mywiki.wooledge.org/ParsingLs그리고왜 `ls`를 구문 분석하지 *않나요*(그리고 어떻게 수행합니까)?) 따라서 이 도구는 실패할 것입니다.
답변2
사용 중인 명령이나 이 출력이 나타나는 이유를 표시하지 않았지만 목표가 일치하는 모든 파일과 디렉터리를 나열하는 것이라면 /etc/cron*
대신 다음을 사용할 수 있습니다 find
.
find /etc/cron*
또는 전체 목록을 원하는 경우(GNU find
):
find /etc/cron* -ls
어느 find
:
find /etc/cron* -exec ls -ld {} +
내 Arch Linux의 샘플 출력은 다음과 같습니다.
$ ls /etc/cron*
/etc/cron.deny /etc/crontab /etc/crontab~ /etc/crontab.pacnew
/etc/cron.d:
0hourly
/etc/cron.daily:
/etc/cron.hourly:
0anacron
/etc/cron.monthly:
/etc/cron.weekly:
그리고 find
:
$ find /etc/cron* -ls
262172 4 drwxr-xr-x 2 root root 4096 Jan 23 19:41 /etc/cron.d
263666 4 -rw-r--r-- 1 root root 128 Jan 14 14:59 /etc/cron.d/0hourly
262173 4 drwxr-xr-x 2 root root 4096 Sep 30 11:38 /etc/cron.daily
262618 4 -rw-r--r-- 1 root root 74 Jan 14 14:59 /etc/cron.deny
262174 4 drwxr-xr-x 2 root root 4096 Jan 23 19:41 /etc/cron.hourly
263665 4 -rwxr-xr-x 1 root root 843 Jan 14 14:59 /etc/cron.hourly/0anacron
262175 4 drwxr-xr-x 2 root root 4096 Jun 30 2016 /etc/cron.monthly
262632 0 -rw-r--r-- 1 root root 0 Oct 31 2017 /etc/crontab
262633 4 -rw-r--r-- 1 root root 49 Sep 22 2017 /etc/crontab~
272465 4 -rw-r--r-- 1 root root 119 Jan 14 14:59 /etc/crontab.pacnew
262176 4 drwxr-xr-x 2 root root 4096 Sep 30 11:38 /etc/cron.weekly
275802 4 -rwxr--r-- 1 root root 68 Sep 30 11:37 /etc/cron.weekly/clamscan.sh
답변3
솔루션TXR 불분명한 음성.
ls
이 출력을 어딘가에서 얻었고 이를 사용해야 한다는 사실을 당연하게 여기십시오 . 원래의 시간과 기계로 돌아가서 다른 형식으로 정보를 얻을 수는 없습니다.
$ txr lsdata.tl < lsdata
-rw-r--r-- 1 root root 128 May 15 2020 /etc/cron.d/0hourly
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.d/sysstat
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.daily/sysstat
어디 lsdata.tl
:
(let ((curdir ""))
(whilet ((line (get-line)))
(match-case line
(`@dir:` (set curdir dir))
(`@{metadata 39} @name` (put-line `@metadata @curdir/@name`)))))
완벽하지는 않습니다. 로 끝나는 이름으로 속일 수 있습니다 :
. 디렉토리 라인 영역이 항상 절대 경로라고 가정할 수 있다면 이를 일치 항목에 포함할 수 있습니다.
(let ((curdir ""))
(whilet ((line (get-line)))
(match-case line
(`/@dir:` (set curdir dir))
(`@{metadata 39} @name` (put-line `@metadata /@curdir/@name`)))))
답변4
원하는 것이 무엇인지 확실하지 않지만 다음 명령을 시도해 보십시오.
$ ls -la | awk -v path=$PWD '{$NF=path"\/"$NF;print}' |sed 's| /| \t/|g'
경로 정렬에 관심이 없다면 sed 부분을 제거할 수 있습니다.