특정 날짜에 다른 Linux 시스템의 파일 목록이 있으므로 고유한 파일을 검색하여 다른 디렉토리에 배치해야 합니다. 여기서 "고유"는 두 번째 파일 이름까지를 의미하므로 _
아래 예에서는 100001_ABC
.100001_XYZ
100001_ABC_25Sep2020_1200-25Sep2020_1300.csv
100001_XYZ_30Sep2020_1300-30Sep2020_1400.csv
100001_XYZ_30Sep2020_1400-30Sep2020_1500.csv
이 디렉터리에 고유한 이름의 파일을 배치하고 싶습니다.
/home/vikrant_singh_rana/uniquefiles/
스크립트는 다음 파일만 복사해야 합니다.
100001_ABC_25Sep2020_1200-25Sep2020_1300.csv
100001_XYZ_30Sep2020_1300-30Sep2020_1400.csv
이것은 내 쉘 스크립트입니다
#!/bin/bash
set +o posix
#reading file names into file_array
readarray -t file_array < <(
cd "/home/vikrant_singh_rana/unzipfiles"
printf "%s\n" * | cut -d"_" -f2 | cut -d"-" -f1 | sort -u )
#print items of array
printf '%s\n' "${file_array[@]}"
for i in "${file_array[@]}"; do
#echo $i
find /home/vikrant_singh_rana/unzipfiles/ -type f -name "*$i*.csv" -exec awk '!seen[$0]++' {} +
done
스크립트는 고유 이름을 올바르게 찾았지만 이를 다른 디렉터리로 이동하는 방법을 찾을 수 없습니다.
답변1
그리고 zsh
.
typeset -A files
for f (*_*_*.csv(.On)) files[${(M)f#*_*_}]=$f
mv -- $files target-directory/
glob .
한정자는 다음으로 제한됩니다.정기적인파일을 On
역순으로 정렬하여 최종 연관 배열에 주어진 키에 대한 알파벳 순서로 첫 번째 파일(여기서는 두 번째 파일까지의 부분)이 포함됩니다 _
.
아마도 어휘 순서가 아니라 수정 시간을 o
기준 으로 정렬하고 싶을 것입니다 m
( 100001_XYZ_01Oct2020_0000-01Oct2020_0100
이렇게 될 경우)앞으로 100001_XYZ_30Sep2020_2200-30Sep2020_2300
예를 들어 어휘적으로), 첫 번째 파일 대신 가장 오래된 파일을 어휘적으로 이동하도록 대체 On
( 최신 파일부터 가장 오래된 파일 순으로 정렬)합니다.om
또는 파일 이름의 첫 번째 타임스탬프를 기준으로 정렬 순서를 정의할 수 있습니다.
zmodload zsh/datetime
bydate() strftime -rs REPLY %d%b%Y_%H%M ${${REPLY%-*}#*_*_}
/ nO+bydate
대신 사용하세요 .On
om
GNU 도구를 사용하면 bash
다음과 유사한 작업을 수행할 수 있습니다(이에 국한되지 않음).정기적인파일이지만 수정 시간별로 정렬되지 않음):
shopt -s failglob
printf '%s\0' *_*_*.csv | sort -zsmut_ -k1,2 | xargs -r0 mv -t target-dir --
(모두 -z
, -s
, -r
, -0
는 -t
GNU 확장입니다.)
파일 이름에서 추출된 타임스탬프를 기준으로 정렬하는 방법은 다음과 같습니다.
printf '%s\0' *_*_*.csv |
# key year month day HHMM
LC_ALL=C sort -zt_ -k1,2 -k3.6,3.9n -k3.3,3.5M -k3.1,3.2n -k3.11,3.14n |
LC_ALL=C sort -zsmut_ -k1,2 |
xargs -r0 mv -t target-dir
만약에, 만약에열쇠의 경우 첫 번째와 두 번째 항목 사이의 부분을 (또는 ) 또는 로 바꿔야 _
합니다 .${(M)f#*_*_}
${${f#*_}%%_*}
${${(s[_])f}[2]}
-k1,2
-k2,2
답변2
모든 파일 이름에 대한 솔루션은 다음과 같습니다.
target_dir="path/to/dir"
find -maxdepth 1 -type f -name '*.csv' -print0 | sort -z | awk '
BEGIN {RS=ORS="\0"; FS=OFS="_"}
!seen[$2]++' | xargs -r0 echo mv -t "$target_dir" --
파이프를 통해 파일 이름을 보호하고, sort
파일 이름을 알파벳순으로 정렬하고, GNU awk
중복 항목을 제외하기 위해 null 구분 기호를 사용합니다. 테스트하고 합리적인 이동 명령이 인쇄되면 삭제 echo
하여 실행하세요.
(또한 위의 모든 null 구분 기호는 GNU 확장입니다. 예를 들어 -z
등)
파일 이름이 좋으면 더 쉬울 것입니다. 간단히 다음을 수행할 수 있습니다.
ls -1 *.csv | awk -F_ '!seen[$2]++' | xargs -d'\n' echo mv -t target/dir --
glob은 파일을 알파벳순으로 가져옵니다.
답변3
나는 배열을 사용하여 본 이름을 보관하고 "새" 이름만 이동합니다.
declare -A seen=()
name_seen='seen[$name]++' # work around to avoid ACE vulnerability
for i in /home/vikrant_singh_rana/unzipfiles/*_*_*; do
name=${i##*/} # remove directory part
name=${name%"_${name#*_*_}"} # retain first two fields
(( name_seen )) || mv -- "$i" /home/vikrant_singh_rana/uniquefiles/
done
답변4
배열, 루프를 사용하거나 옵션(GNU 버전)과 awk
같은 내장 도구를 사용하는 이유는 무엇입니까 ?uniq
-w
mv $(ls *csv|uniq -w 10) /home/vikrant_singh_rana/uniquefiles/