find
AIX에서 이 명령을 사용하여 다음으로 끝나는 파일을 제외하려고 하며 .gz
목록에서 마지막 2줄도 제외해야 합니다. 예를 들어, 디렉토리에는 다음이 있습니다.
shop14_0_Log0002019754.gz
shop14_0_Log0002019755.gz
shop14_0_Log0002019756.gz
shop14_0_Log0002019757
shop14_0_Log0002019758.gz
shop14_0_Log0002019759.gz
shop14_0_Log0002019760.gz
shop14_0_Log0002019761.gz
shop14_0_Log0002019762
압축되지 않은 파일만 검색하고 하단의 마지막 2개 파일을 제외하여 아래와 같은 출력을 얻고 싶습니다.
출력 명령은 다음에 도달해야 합니다.
shop14_0_Log0002019757
해당 명령을 사용하여 마지막 두 줄을 제외 할 수 있지만 ls
이름이 로 끝나는 파일을 제외하려면 어떻게 해야 합니까 .gz
? AIX/UNIX에서 이 작업을 수행할 수 있는 방법을 찾으려고 합니다.
ls -ltr | awk '{print $9} | sed '$d' | sed '$d'
를 사용하면 목록에서 제외하여 압축되지 않은 파일 목록을 find
얻을 수 있지만 .gz
여기에는 원하지 않는 마지막 두 파일이 포함되어 있습니다.
find . -type f ! -name '*\.gz' -print
위 find
명령은 다음을 반환합니다.
./shop14_0_Log0002019757
./shop14_0_Log0002019762
해당 파일은 shop14_0_Log0002019762
목록에서 제외되어야 하며 shop14_0_Log0002019761
, 압축되지 않은 경우에도 목록에서 제외되어야 합니다.
제외할 "마지막 2개" 항목은 파일 수정 시간을 기준으로 정렬됩니다. 나의 궁극적인 목표는 압축되지 않은 파일을 압축하는 것입니다.
어떻게 해야 하나요?
답변1
Bash를 사용하고 있고 파일 이름에 개행이나 공백이 포함되지 않을 것이라고 100% 확신하는 경우 다음을 수행할 수 있습니다.
shopt -s extglob
ls -t !(*gz) | tail -n +3 | while IFS= read -r file; do gzip "$file"; done
확장된 와일드카드를 활성화 하여 "gz로 끝나지 않음"을 shopt -s extglob
제공합니다 . !(*gz)
그런 다음 를 사용하여 ls -t
수정 시간을 기준으로 최신 항목부터 정렬합니다. 이는 tail -n +3
"세 번째 줄부터 시작하는 모든 내용을 인쇄"한다는 의미이므로 처음 두 파일은 건너뜁니다. 마지막으로 파일의 루프 while
에 파이프합니다 . gzip
또는 다음을 수행할 수 있습니다.
gzip $(ls -t !(*gz) | tail -n +3)"
또는
ls -t !(*gz) | tail -n +3 | xargs gzip
이는 파일 이름이 올바른지 확신할 수 있는 경우에만 작동합니다. 바라보다https://mywiki.wooledge.org/ParsingLsls
구문 분석된 출력이 권장되지 않는 이유
답변2
.gz
마지막 2개 파일을 제거하기 전이나 후에 파일을 제외해야 하는지 는 확실하지 않습니다 . 이전의 경우 예제에 두 개의 파일만 남아 있고 둘 다 생략해야 하므로 출력은 비어 있지만 shop14_0_Log0002019757
"이후"를 가정하여 작업을 해결했습니다.
해결 방법 1, 세게 누르기:
#!/bin/bash
files=(*)
newest_1=${files[0]}
newest_2=${files[0]}
for f in "${files[@]}"; do
if [[ $f -nt $newest_1 ]]; then
newest_2=$newest_1
newest_1=$f
elif [[ $f -nt $newest_2 ]]; then
newest_2=$f
fi
done
if [[ $newest_1 == "$newest_2" ]]; then
filenames=$newest_1
else
filenames="${newest_2}\n${newest_1}"
fi
echo -e "$filenames" | sed '/\.gz$/d'
해결 방법 2:AIX에서는 기본적으로 사용할 수 없는 GNU 유틸리티를 사용하십시오. 그러나 이는 방법을 시연하는 데 유용할 수 있습니다.
find . -maxdepth 1 ! -name '.' -printf "%A@ %f\n" | sort -g | head -n -2 | cut -d' ' -f2 | sed '/\.gz/d'
설명하다
find .
- 현재 디렉토리에서 찾기-maxdepth 1
- 재귀 없음, 레벨 1만 해당! -name '.'
- 현재 디렉토리 항목 제외(.
)-printf "%A@ %f\n" |
- 분수 부분과 파일 이름을 포함하여 1970년 이후 파일의 마지막 액세스 시간을 초 단위로 출력합니다.sort -g |
- 부동 소수점 숫자로 정렬head -n -2 |
- 마지막 2줄을 제외한 모든 줄 출력cut -d' ' -f2 |
- 첫 번째 열만 잘라서 파일 이름을 유지합니다.sed '/\.gz$/d'
.gz
- 파일 삭제 .
답변3
find 명령 사용을 선호한다고 가정하면 다음과 같이 문제가 해결될 수 있습니다.
find . -type f ! -name '*\.gz' -print | awk '{Q[N++]=$0; N=N%3; if (Q[N]!="") {print Q[N]}}
awk 명령은 길이가 n인 배열 Q를 채웁니다.
- 물어보세요[N++]
배열을 통해 모듈로 3으로 진행합니다(배열이 길수록 더 많은 요소를 건너뛸 수 있음).
- N=N%3
이전에 채워졌던 삽입된 2개의 항목을 인쇄합니다(따라서 마지막 2개는 무시됩니다). if는 배열이 완전히 초기화되지 않은 경우 첫 번째 삽입을 건너뜁니다.
123 123 123 123 123 ...
^^ ^^ ^ ^ ^^ ^^
|| || | | || ||
io io O i iO iO
nu nu U n nU nU
t t T T T
"ls"를 사용하려는 경우 $0을 n번째 요소로 변경할 수 있습니다(이 경우 파일 이름에 공백이 있으면 안 됩니다). 귀하가 겪고 있는 문제의 극단적인 경우를 제가 완전히 이해하고 있는지 확신할 수 없으므로 확인하시기 바랍니다.
답변4
ksh93 셸(최신 AIX 버전의 표준)을 사용하여 배열을 지원하고 파일이 수정 시간 순서로 확장된다고 가정하면(즉, 파일 이름 순서가 수정 타임스탬프와 동일한 순서를 나타냄) 전체 파일을 얻을 수 있습니다. 배열 목록을 사용하고(나중에 "마지막 두 개"를 추출하는 데 유용함) 다른 배열을 사용하여 압축되지 않은 모든 파일을 찾습니다. 최종 파일 목록은 압축되지 않은 파일 목록을 반복하고 이전 "마지막 두 개"와 일치하는 모든 파일을 제거하여 수집됩니다.
#!/usr/bin/ksh93
files=(*)
uncompressed=( !(*.gz) )
for index in "${!uncompressed[@]}"
do
if [[ "${uncompressed[index]}" == "${files[-1]}" ]] || \
[[ "${uncompressed[index]}" == "${files[-2]}" ]]
then
unset -v 'uncompressed[index]'
fi
done
# echo gzip "${uncompressed[@]}"
마지막에는 "uncompressed"라는 배열이 있습니다. 표시된 대로 이러한 파일 이름을 압축할 수 있습니다(remove echo
).