내 Unix 폴더에 /home/TRANS라는 파일이 여러 개 있습니다.
이 폴더는 매달 파일을 받습니다. 파일 이름은 다음과 같습니다.
- ENCD_213_E-DM_CCA_ID3490_A01.txt
- ENCD_213_E-DM_CCA_ID33120_A01.txt
- ENCD_213_E-DM_CCA_IDP3664_A01.txt
- ENCD_213_E-DM_CCA_ID3327_A01.txt
- ENACT_215_E_DM_CCA_IDA33320_25OCT2017.csv
- ENACT_215_E_DM_CCA_IDA31116_25OCT2017.csv
이름을 바꾼 후 최종 출력은 다음과 같습니다.
- id3490.txt
- id33120.txt
- idp3664.txt
- id3327.txt
- ida33320.csv
- ida31116.csv
따라서 기본적으로 TRANS 폴더의 모든 파일 이름에서 다음 문자열을 바꾸고 최종 출력 파일 이름을 소문자로 만들고 싶습니다.
- ENCD_213_E-DM_CCA_
- _A01
- ENACT_215_E_DM_CCA_
- _2017년 10월 25일
한 줄 명령이나 쉘 스크립트에서 이 작업을 어떻게 수행할 수 있습니까? 여러 질문을 확인했지만 소문자로 변경하는 것 외에 여러 문자를 대체할 수 없습니다. 저는 Unix를 처음 접했기 때문에 여러분의 도움이 필요합니다.
답변1
이를 수행하는 방법에는 여러 가지가 있습니다. 귀하의 예에 적합한 명령은 다음과 같습니다.
for oldname in *; do
newname="$(echo "${oldname}" | grep -Po 'ID\w?\d+' | tr A-Z a-z).txt" \
&& mv -i "${oldname}" "${newname}";
done
grep
이 예 에서는 지원하지 않는 것으로 보이는 Perl 호환 정규식을 사용합니다 . 다음은 기본 정규식을 사용하는 대안입니다.
for oldname in *; do
newname="$(echo "${oldname}" | grep -o 'ID[A-Z]\?[0-9]\+' | tr A-Z a-z).txt" \
&& mv -i "${oldname}" "${newname}";
done
아래는 좀 더 자세한 설명입니다.
이 표현은 다음 for oldname in *
을 사용합니다.와일드카드 패턴/와일드카드현재 디렉터리의 파일을 반복하고 각 이름을 oldname
변수에 저장합니다. 이를 테스트하려면 다음 명령을 실행할 수 있습니다.
for oldname in *; do echo "${oldname}"; done
grep
그런 다음 유지하려는 파일 이름 부분을 추출하는 데 사용합니다 . 옵션 -P
플래그는 grep
Perl 호환 정규식을 사용하도록 지시하고(이 경우에는 실제로 필요하지 않음) 플래그 는 전체 문자열을 인쇄하는 대신 일치하는 하위 문자열만 추출 -o
하도록 지시합니다 . grep
패턴 \w?
은 옵션의 단일 문자("단어" 문자)와 일치하고 \d+
패턴은 하나 이상의 숫자와 일치합니다. 다음과 같이 정규식을 테스트할 수 있습니다.
for oldname in *; do echo "${oldname}" | grep -Po 'ID\w?\d+'; done
그런 다음 tr
다음을 사용하여 대문자를 소문자로 변환합니다.
for oldname in *; do echo "${oldname}" | grep -Po 'ID\w?\d+' | tr A-Z a-z; done
다음 단계는 사용하는 것입니다.명령 대체이 문자열을 변수에 할당하고 결과를 인쇄합니다.
for oldname in *; do
newname="$(echo "${oldname}" | grep -Po 'ID\w?\d+' | tr A-Z a-z)" && echo "${newname}"
done
그런 다음 ".txt" 파일 확장자를 추가합니다.
for oldname in *; do
newname="$(echo "${oldname}" | grep -Po 'ID\w?\d+' | tr A-Z a-z).txt" && echo "${newname}"
done
이 명령을 온전성 검사로 실행하여 예상한 결과를 얻을 수 있는지 확인할 수 있습니다. 만족스러우면 echo
해당 명령을 다음으로 바꿉니다 mv
.
for oldname in *; do
newname="$(echo "${oldname}" | grep -Po 'ID\w?\d+' | tr A-Z a-z).txt" \
&& mv -i "${oldname}" "${newname}";
done
답변2
find
+bash
해결책:
find . -type f -regextype posix-egrep \
-regex ".*EN(ACT|CD)_[0-9]+_E(-|_)DM_CCA_.+[0-9]\.(txt|csv)$" -exec bash -c \
'fn=${0##*/}; dir_n="${0%/*}/";
[[ "$fn" =~ .*_(ID[^_]+)_.*\.(txt|csv)$ ]];
mv "$0" "$dir_n${BASH_REMATCH[1],,}.${BASH_REMATCH[2]}"; ' {} \;
답변3
파일 이름 조작의 경우 bash 매개변수 확장이 좋습니다. 바라보다이것좋은 개요를 얻으려면.
기본적으로 파일의 ID 부분을 유지하려고 하므로 다음과 같이 할 수 있습니다.
#!/bin/bash
for f in *csv *txt; do
ext="${f##*.}"
if [[ $f =~ ID[[:alnum:]]+ ]]; then
mv "$f" "${BASH_REMATCH,,}.${ext}"
fi
done
exit
이는 각 csv 및 txt 파일을 반복하고 PE를 사용하여 확장자를 가져옵니다. 그런 다음 bash 정규식 일치 연산자를 사용하여 =~
파일 이름이 패턴과 일치하는지 확인하세요. 그렇다면 bash는 $BASH_REMATCH
정규식이 일치하는 내용으로 이를 채울 것입니다. 그런 다음 파일은 원래 확장자가 추가된 해당 일치 항목의 소문자 버전으로 이동됩니다. 모든 샘플 파일을 생성하고 예상한 결과를 얻었습니다.