![콘텐츠 패턴 일치를 기반으로 파일을 디렉터리로 이동합니다.](https://linux55.com/image/199875/%EC%BD%98%ED%85%90%EC%B8%A0%20%ED%8C%A8%ED%84%B4%20%EC%9D%BC%EC%B9%98%EB%A5%BC%20%EA%B8%B0%EB%B0%98%EC%9C%BC%EB%A1%9C%20%ED%8C%8C%EC%9D%BC%EC%9D%84%20%EB%94%94%EB%A0%89%ED%84%B0%EB%A6%AC%EB%A1%9C%20%EC%9D%B4%EB%8F%99%ED%95%A9%EB%8B%88%EB%8B%A4..png)
files
특정 콘텐츠가 포함된 기존 디렉터리의 파일을 호출하는 스크립트를 작성하여 기존 또는 새 디렉터리 및 하위 디렉터리 로 이동하고 해당 파일을 dir/subdir로 이동하고 싶습니다 .fruit
~/bin
files
예를 들어, file1 file2 file3.... file100이라는 기존 디렉터리에 많은 일반 파일이 있습니다 .
ls
:
file1
file2
file3
file4
...
file100
파일 내용은 다음과 같습니다.
cat file1
apple 1
789098
cat file2
orange 2
389342
cat file3
pear 1
678034
cat file4
grapes 3
123432
cat file5
apple 3
342534
cat file6
apple 3
234298
field1의 첫 번째 줄이 동일한 파일을 field1과 동일한 이름을 가진 새 디렉터리로 이동하고 파일 이름은 변경하지 않고 싶습니다.
- 즉
file1
,file5
,file6
로 이동apple
file2
가다orange
file3
가다pear
- 등.
ls
:
apple pear grapes orange etc ...
./apple:
file1 file5 file6
./pear:
file3
/orange:
file2
그런 다음 새 하위 디렉터리를 만들고 field2 콘텐츠의 첫 번째 줄이 동일한 파일을 해당 하위 디렉터리로 이동하려고 합니다.
- 디렉토리 아래에서
apple
하위file1
디렉토리로 이동하고1
,file5
하위 디렉토리로 이동하고3
,file6
하위 디렉토리로 이동합니다.3
- 디렉토리 아래에서 하위 디렉토리로 이동합니다
orange
.file2
2
- 디렉토리 아래에서 하위 디렉토리로 이동합니다
pear
.file3
1
- 등.
정렬 및 이동 후 파일은 다음과 같이 정렬되어야 합니다.
ls
:
apple pear grapes orange etc ...
./apple:
1 3
./apple/1:
file1
./apple/3:
file5 file6
./orange:
2
./orange/2:
file2
./pear
1
./pear/1
file3
vi 편집기를 사용하여 모든 파일을 반복하고 이를 쉘의 해당 디렉터리 및 하위 디렉터리로 이동하려면 어떻게 해야 합니까?
답변1
$ find . -name 'file*'
./file6
./file1
./file5
./file2
./file3
./file4
$ perl -lane '
close(ARGV);
mkdir $F[0] unless -e $F[0];
mkdir "$F[0]/$F[1]" unless -e "$F[0]/$F[1]";
rename $ARGV, "$F[0]/$F[1]/$ARGV" if (-d "$F[0]/$F[1]");
' file*
$ find . -name 'file*'
./pear/1/file3
./grapes/3/file4
./orange/2/file2
./apple/1/file1
./apple/3/file5
./apple/3/file6
file{1..6}
샘플 파일입니다. Perl 스크립트는 각 파일을 차례로 열고 첫 번째 줄을 읽고 이를 배열로 분할합니다 @F
(Perl의 -a
명령줄 옵션을 통해). 그런 다음 파일을 닫고(라인 카운터를 재설정하는 부작용이 있음 $.
) 디렉토리를 생성하고(아직 존재하지 않는 경우) 파일을 디렉토리로 이동합니다(실제로 디렉토리인 경우). 이미 존재하는 경우 일반 파일, 심볼릭 링크 또는 디렉터리가 아닌 다른 것일 수 있습니다.
한 줄 이상 없는 파일은 무시됩니다. 예상과 다른 형식의 파일(예: 첫 번째 줄에는 기본 디렉터리 이름과 하위 디렉터리 이름을 포함하여 모든 종류의 공백으로 구분된 두 개의 필드가 포함되어 있음)은 정의되지 않은(아마도 이상하거나 재앙적일 수 있는) 결과를 초래할 수 있습니다.
이 두 find
명령은 Perl one-liner를 실행하기 전후에 파일 위치를 표시하는 데 사용됩니다. 이는 출력을 생성하지 않는 최소한의 스크립트입니다. 또한 오류 검사나 데이터 유효성 검사도 충분하지 않습니다.
독립 실행형 스크립트로서의 대체 버전입니다. 이 글을 쓰는 유일한 진짜 이유는
Perl 옵션에 대한 Stéphane의 의견을 다루기 위한 것입니다 -T
(대부분의 경우 문제가 되지 않습니다... 하지만 사람들은 파일 이름을 사용하여 병적으로 미친 짓을 하고 심지어 악의적인 일도 하므로 조심하세요. /잘못된 것은 없습니다.) 편집증이 있음):
$ cat sort-move.pl
#!/usr/bin/perl
use strict;
use File::Path qw(make_path);
while(<<>>) {
my($dir,$subdir) = split;
close(ARGV);
make_path("$dir/$subdir");
rename $ARGV, "$dir/$subdir/$ARGV" if (-d "$dir/$subdir");
}
예를 들어 실행해 보세요 ./sort-move.pl file*
. 디렉터리 생성 오류가 이제 치명적인 조건이라는 점을 제외하면 결과는 한 줄 버전과 정확히 동일합니다.
추가 오류 검사나 데이터 유효성 검사는 수행하지 않습니다. 실제로는 더 적은 작업을 수행합니다( 디렉토리를 생성하기 위해 make_path()
핵심 Perl 모듈 File::Path
의 기능 에 의존합니다. make_path()
매우 유사하게 작동합니다 mkdir -p
). 즉, 나쁜 데이터는 여전히 나쁜 일을 하게 만들 것이므로 나쁜 데이터를 제공하지 마십시오.
그러나 이미 존재하고 디렉토리가 아니어서(또는 파일 시스템 공간 부족이나 inode 부족과 같은 다른 이유로 인한 오류로 인해) 실패하는 경우 make_path
이제 스크립트는 오류 메시지와 함께 즉시 종료됩니다. "$dir/$subdir"
예를 들어, mkdir apple; touch apple/1
이전에 이 스크립트를 실행했다면 오류 메시지는 다음과 같을 것입니다 mkdir apple/1: File exists at ./sort-move.pl line 9.
. 스크립트는 디렉터리를 생성하지 않으며 파일을 이동하지 않습니다. 나는 그것을 테스트하기 위해 정확히 그랬기 때문에 이것을 알고 있습니다.
전체 스크립트는 오류 조건을 적절하게 처리합니다. 전체 스크립트에는 내용만 표시하는 -n
또는 옵션도 있습니다.--dry-run
회의실제로 하지 않고도 그냥 해보세요. 이것은 완전한 스크립트는 아니지만가장 작은원하는 것을 수행하는 한 가지 방법의 실제 예입니다.
답변2
zsh
쉘 사용 ( vi
귀하의 요청에 따라 대부분의 쉘과 같은 줄 편집 모드가 있지만 이것이 어떻게 관련되는지는 알 수 없습니다):
typeset -A files=()
for file (file*(N.L+3))
read -r dir subdir ignore < $file &&
[[ $dir != (|.|..|*/*) ]] &&
[[ $subdir != (|.|..|*/*) ]] &&
files[$dir/$subdir]+=$file$'\0'
if (($#files))
mkdir -p -- ${(k)files} &&
for dir (${(k)files}) mv -i -- ${(0)files[$dir]} $dir/
files
위는 A
키가 대상 디렉토리인 연관 배열이며, 일치하는 각 파일의 첫 번째 줄의 처음 두 개의 IFS 구분 필드로 구성됩니다 file*(N.L+3)
(이름은 file
일반 ( .
)으로 시작하고 L
3보다 깁니다( x y\n
크기 4는 한 줄입니다). 두 개의 필드를 포함하는 파일)).
보호 조치로 .
빈 ..
디렉토리 구성 요소나 포함을 허용하지 않습니다 /
.
연관 배열 요소의 값은 지정된 대상 디렉토리에 있는 NUL로 구분된 파일 목록입니다.
그런 다음 이러한 모든 디렉터리를 한 번에 생성하고 성공한 후에만 해당 디렉터리에서 파일 이동을 시작합니다.
답변3
나는 이것을 하고 싶습니다(Bash 또는 POSIX-y 쉘에서):
for f in ./*; do
read -r a b < "$f"
mkdir -p -- "$a/$b"
mv -- "$f" "$a/$b"
done
즉, 파일( read
한 줄)을 반복하고 두 개의 필드로 분할하고 해당 필드를 기반으로 디렉터리를 만든 다음 파일을 해당 디렉터리로 이동합니다. 필요에 따라 상위 디렉터리를 -p
생성 mkdir
하고 기존 디렉터리를 무시하는 옵션입니다.
예, 각 파일에 대해 한 번씩 호출되므로 추가 작업이 수행됩니다. 예, mkdir
파일 에 .mv
/dev/foo
예제 파일에서 이를 실행하면 다음이 제공됩니다.
$ ls -R
.:
apple/ grapes/ orange/ pear/
./apple:
1/ 3/
./apple/1:
file1
./apple/3:
file5 file6
./grapes:
3/
[...]