센트OS 5.9
다양한 임의의 디렉토리에 foo.ext.gz 파일이 있는 서버가 있습니다.
예:
- /opt/fooapp/foosubdirectory/foo_randomnumber/blah/blah/foo.ext.gz
- /opt/fooapp/foosubdirectory/foo_ Differentrandomnumber/blah/blah/foo.ext.gz
- /opt/fooapp/foosubdirectory/foo_another 다른 난수/blah/blah/foo.ext.gz
bash 명령을 실행하여 다음을 수행하고 싶습니다.
- foo.ext.gz 파일 찾기
- gz 파일의 내용 추출해당 GZ 파일과 동일한 디렉터리에 있음
- 원본 gz 파일을 그대로 유지하세요.
이 작업을 수동으로 수행하려면 find / -iname foo.ext.gz
. 그런 다음 파일이 있는 디렉터리를 복사하고 다음과 같이 입력합니다.
gunzip -c /opt/fooapp/foosubdirectory/foo_12345/blah/blah/foo.ext.gz > /opt/fooapp/foosubdirectory/foo_12345/blah/blah/foo.ext
여기서 문제는 수십 개의 파일/디렉터리에 대해 이 프로세스를 수동으로 수행해야 한다는 것입니다.
xargs 또는 for 루프를 활용하는 방법이 있습니까?
답변1
의 출력을 구문 분석할 수 있지만 find
공백 등을 처리해야 합니다. 불행하게도 보존할 / 플래그 gunzip
가 없습니다 ( 및 와 마찬가지로 ).--keep
-k
bzip2
xz
gunzipkeep
하나의 인수(gzip 파일)를 사용하여 압축을 푸는 작은 스크립트를 만들고 싶다면 $PATH 어딘가에 스크립트를 넣고 다음과 같이 호출하세요.
find /opt/fooapp/foosubdirectory -name "foo.ext.gz" -print0 | xargs -0 --norun-if-empty --max-args 1 gunzipkeep
스크립트는 다음과 같습니다.
#!/bin/bash
inname=$1
outname=${inname%.gz}
gunzip -c "$inname" > "$outname"
답변2
다른 답변에서와 같이 도우미 스크립트(또는 bash 함수)를 사용하지 않고 이 작업을 수행하는 것은 어렵지만 불가능하지는 않습니다. 여기에서는 -execdir
옵션 find
과 일부 매개변수 확장이 사용됩니다 bash
.
find /opt/fooapp/foosubdirectory -name '*.gz' -execdir /bin/bash -c 'pwd ; echo ${0%.gz}; cp ${0} ${0%.gz}.tmp.gz ; gunzip ${0%.gz}.tmp.gz ; mv ${0%.gz}.tmp ${0%.gz}' {} \;
[편집] 참고: 이 특정 매개변수 확장을 위해서는 최신 버전이 필요 bash
하지만 일부 이전 버전에는 이 기능이 없습니다. V 3.2.x에서 테스트했습니다.
[편집] 참고 2: -execdir
내가 아는 한 이 표현은 GNU find
(및 기타 최신 구현)에는 존재하지만 이전 구현에는 존재하지 않습니다. 나는 이것을 GNU find v 4.2.x에서 테스트했습니다.
가독성과 주석을 위해 동일하게 다시 작성했습니다.
find /opt/fooapp/foosubdirectory
-name '*.gz'
-execdir /bin/bash -c '_bash_command_string_ ' {} \;
# This ^ will run bash from the subdirectory containing the matched file
_bash_command_string_ -->
pwd ; # we are working in this subdir
echo ${0%.gz}; # this is matched filename (minus final .gz)
cp ${0} ${0%.gz}.tmp.gz ; # copy the .gz file as .tmp.gz
gunzip ${0%.gz}.tmp.gz ; # gunzip the .tmp.gz as .tmp
mv ${0%.gz}.tmp ${0%.gz} # rename .tmp as matched filename (minus final .gz)
이 솔루션은 영리한 솔루션으로서 흥미롭지만 실제로 사용하기에는 너무 복잡할 수 있습니다.
바라보다Bash 참조 - 쉘 매개변수 확장, 찾다 ${parameter%word}
.
답변3
bash ≥4, shopt -s extglob
재귀 **/
디렉터리 탐색을 실행합니다. (이것은 디렉토리로 심볼릭 링크를 통과한다는 점에 유의하십시오. zsh에서는 특별한 설정이 필요하지 않으며 **/
심볼릭 링크로 드롭다운되지는 않지만 ***/
그렇게 됩니다.) 그런 다음 간단한 루프로 충분합니다.
err=
for z in **/*.gz; do
gunzip <"$z" >"${z%.gz}" &&
touch -r "$z" "${z%.gz}" || # if you want to retain the file's modification time
err=1
done
if [ -n "$err" ]; then echo >&1 'Watch out, there were errors!'; fi
POSIX만을 사용하여 sh
쉘에서 호출하십시오 find
. 오류 상태를 추출하는 것이 더 어렵습니다. 명령이 stderr에서 어떤 것을 생성했는지 확인하십시오.
find . -name '*.gz' -exec sh -c '
for z do gunzip <"$z" >"${z%.gz}" && touch -r "$z" "${z%.gz}"; done
' _ {} +
답변4
find . -name \*.gz | parallel gzip -dc {} \> {.}
{.}
확장이 없는 입력 라인입니다.- 기본 구분 기호는 개행 문자입니다.
find . -name \*.gz | while read f; do gzip -dc "$f" > "${f%.gz}"; done
- 입력 줄이 IFS의 문자로 시작하거나 끝날 수 있거나 백슬래시를 포함할 수 있는지
IFS=
여부를 추가합니다.-r