한 위치에서 다른 위치로 파일을 복사하려고 합니다. 다음은 몇 가지 예입니다.
aaa_bbb_ccc_ddd_cost_code_20140330.gz
aaa_bbb_ccc_ddd_revenue_zone_20140329.gz
aaa_bbb_ccc_ddd_benefit_extract_20140330.csv.gz
aaa_bbb_ccc_ddd_profit_zone_20150509.csv.gz
aaa_bbb_ccc_ddd_loss_zone_20140330.csv
aaa_bbb_ccc_ddd_username.csv.gz
위 목록에서 복사해야 하는 파일은 다음 형식이어야 합니다.
aaa_bbb_ccc_ddd_cost[or]revenue[or]benefit[or]profit[or]loss_yyyymmdd.csv.gz
이는 파일을 의미합니다.
aaa_bbb_ccc_ddd_loss_zone_20140330.csv
aaa_bbb_ccc_ddd_username.csv.gz
복사하면 안 됩니다.
또한 변수에 할당해야 하는데 다음과 같이 시도하고 있지만 작동하지 않는 것 같습니다.
FILENAME="egrep 'aaa_bbb_ccc_ddd_(cost|revenue|benefit|profit)_code_[0-9]{8}.csv.gz'"
변수에 할당하려는 이유는 나중에 다음을 수행하기 위해 코드에서 이를 사용해야 하기 때문입니다.
SOURCE_DIR="/temp"
DESTN_DIR="/output"
FILENAME=`egrep 'aaa_bbb_ccc_ddd_(cost|revenue|benefit|profit)_code_[0-9]{8}.csv.gz'`
echo "FILENAME is:" $FILENAME
for SAMPLE_FILE in $(ls "$SOURCE_DIR/$FILENAME")
do
cp $SAMPLE_FILE $DESTN_DIR
done
이것을 달성하는 다른 방법이 있습니까?
답변1
Use find
및 -exec
해당 옵션(여기서는 GNU를 조건 find
자로 사용 -regex
):
find . -regextype posix-egrep -regex '.*/aaa_bbb_ccc_ddd_(cost|revenue|benefit|profit|loss)_[[:alpha:]]+_[0-9]+\.csv\.gz' -exec mv {} "$DESTN_DIR" \;
노트:
find .
find
현재 디렉터리부터 검색할 파일을 알려줍니다 .기본적으로 GNU는
find
emacs 스타일 정규식을 사용합니다. 저는 을 선호-regextype posix-egrep
하지만, 지원되는 익숙한 스타일로 전환할 수 있습니다.정규식을 사용하여 파일을 선택합니다.
-regex '.*/aaa_bbb_ccc_ddd_(cost|revenue|benefit|profit|loss)_[[:alpha:]]+_[0-9]+\.csv\.gz'
표준 접두사aaa_bbb_ccc_ddd_
뒤에 지정된 단어 중 하나(cost|revenue|benefit|profit|loss)
, 지정되지 않은 다른 단어,_[[:alpha:]]+
날짜,_[0-9]+
마지막으로 원하는 확장자가 옵니다.csv.gz
. 이를 미세 조정해야 할 수도 있습니다.발견된 모든 파일은 대상 디렉토리로 이동됩니다
-exec mv {} "$DESTN_DIR" \;
. 일치하는 파일이 발견 되면find
이 명령을 실행하고{}
파일 이름을 바꿉니다. 이는 파일 이름에 공백, 줄 바꿈 또는 기타 읽을 수 없는 문자가 포함된 경우에도 작동합니다.
정규식을 사용하는 기본(emacs) 스타일
GNU 정규식의 기본 스타일에는 find
그룹화 및 대체 연산자의 일부 이스케이프가 필요합니다.
find . -regex '.*/aaa_bbb_ccc_ddd_\(cost\|revenue\|benefit\|profit\|loss\)_[[:alpha:]]+_[0-9]+\.csv\.gz' -exec echo mv {} targetdir \;
애플 컴퓨터
Mac OSX 버전 find
(매뉴얼 페이지는 여기에 있습니다)은 지원되지만 -regex
지원되지는 않습니다 -regextype
. 하지만 정규식 구문에 약간의 변경이 필요하더라도 놀라지 않을 것입니다.
IBM AIX 5
IBM AIX 버전의 매뉴얼 페이지 find
는 다음과 같습니다.여기. 물론아니요지원하다 -regex
.
답변2
그리고 zsh
:
setopt extendedglob
source_dir="/temp"
destn_dir="/output"
pattern='aaa_bbb_ccc_ddd_(cost|revenue|benefit|profit)_code_[0-9](#c8).csv.gz'
print -r "pattern is: $pattern"
cp -- $source_dir/$~pattern $destn_dir
ksh93 패턴은 다음과 같은 방식으로 표현될 수 있습니다.
aaa_bbb_ccc_ddd_@(cost|revenue|benefit|profit)_code_{8}(\d).csv.gz
그리고 ksh88
:
aaa_bbb_ccc_ddd_@(cost|revenue|benefit|profit)_code_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].csv.gz
하지만, 그확장하다POSIX 호환성이 깨지는 것을 방지하기 위해 와일드카드는 변수 내에서 작동할 수 없습니다.
echo @(a)
이는 POSIX에 따른 잘못된 구문이므로 ksh
새로운 glob 연산자로 만들 수 있습니다. 하지만:
x='@(a)'
echo $x
POSIX에서 지정한 것과 정확히 일치하며 현재 디렉터리에서 호출된 파일이 @(a)
아닌 출력(IFS의 기본값 사용)을 의미합니다.a
a
eval
따라서 다음 을 사용해야 합니다.
pattern='aaa_bbb_ccc_ddd_@(cost|revenue|benefit|profit)_code_{8}([0-9]).csv.gz'
print -r "pattern is: $pattern"
eval 'cp -- "$source_dir"/'"$pattern"' "$destn_dir"'
답변3
이 작업은 한 줄로 수행할 수 있습니다.
find /temp -maxdepth 1 -type f | \
grep -P 'aaa_bbb_ccc_ddd_(cost|revenue|benefit|profit)_.*[0-9]{8}' | \
xargs cp -t /output
find
하위 폴더가 없는 폴더의 내용을 나열합니다.grep
당신의 파일 이름cp
대상 디렉터리(-t
) 에 복사 합니다 .
질문이 100% 명확하지 않으므로 정규식을 조정하면 됩니다. 어떤 문서에는 그런 내용이 있고 .csv.gz
, 어떤 문서에는 있고 .csv
, 어떤 문서에는 있습니다 .gz
.
답변4
모든 최신 쉘은 기본 glob 구문을 사용하지 않고 다음과 같이 원하는 것을 직접 지원합니다.
cp aaa_bbb_ccc_ddd_{cost,revenue,benefit,profit,loss}_[0-9]*.csv.gz destination_dir
이는 5개의 인수로 확장되며, 각 인수는 다음 형식의 구체입니다...._keyword_<digits>...
두 번째 질문에 답하기 위해 각 변수를 차례로 변수에 할당하는 방법은 다음과 같습니다.
for FNAME in aaa_bbb_ccc_ddd_{cost,revenue,benefit,profit,loss}_[0-9]*.csv.gz
do
echo $FNAME
if [ -e $FNAME ]
then
cp $FNAME <destination>
fi
done
존재 확인( if [ -e $FNAME ]
)은 5개의 글로브 중 하나라도 일치하지 않는 경우 글로브를 그대로 유지하고 오류 메시지를 받기 때문에 발생합니다.