파일 이름 목록(일부는 공백 포함)을 포함하고, 해당 파일이 속한 전체 파일 경로 목록(공백 포함)을 무작위 순서로 포함하는 두 개의 텍스트 파일 src.txt
및 가 있다고 가정해 보겠습니다 . 예를 들어:dest.txt
src.txt
/src/dir/
dest.txt
src.txt:
file 1.jpg
file_2.html
file 3.jpg
타겟.txt:
/dest/dir 1/file 3.jpg
/dest/file4.txt
/dest/file 5.txt
/dest/dir 2/file 1.jpg
/dest/file_2.html
쉘에서 대량 이동 작업을 수행하는 방법은 무엇입니까? 소스 파일을 반복 하면서 while read
해당 명령을 사용해야 한다고 확신 하지만 여기서는 이것이 필수 인지 필수 mv
인지 잘 모르겠습니다 . 공백 문자 구문 분석 오류가 계속 발생합니다 .grep
sed
cannot stat...
답변1
그리고 zsh
:
src=(${(f)"$(<src.txt)"})
for f (${(f)"$(<dest.txt)"})
(($src[(Ie)$f:t])) && mv /src/dir/$f:t $f
이는 배열의 각 파일을 읽은 다음 배열의 각 요소를 읽습니다."목적지"basename( 모든 선행 경로 이름 구성 요소를 제거하는 수정자)이 다음 :t
인 경우 배열zsh
"원천"배열한 다음 파일을 이동합니다. 연습 실행을 수행하려면 mv
로 바꾸십시오 printf '"%s" -> "%s"\n'
.
이제 다음을 실행할 수도 있습니다(여전히 zsh
).
for f (${(f)"$(grep -Ff src.txt dest.txt)"})
mv /src/dir/$f:t $f
src.txt
in의 파일 이름이 경로 목록의 디렉터리 이름(또는 해당 이름의 일부)과 일치하지 않는 in의 파일 이름 및 in과 같은 경로는dest.txt
(예:한data1
src.txt
/path/data1_dir/some_file
dest.txt
grep
/filename$
F
dest.txt
src.txt
bash
4
readarray -t files < <(sed 's|[[\.*^$/]|\\&|g;s|.*|/&$|' src.txt | grep -f- dest.txt)
for f in "${files[@]}"; do mv /src/dir/"${f##*/}" "$f"; done
답변2
줄 바꿈이 허용되는 구분 기호인 경우 POSIX 셸에서 다음이 안정적으로 작동해야 합니다.
IFS='
';set -f
for f in $(cat <"$destfile")
do [ -e "./${f##*/}" ] ||
[ -h "./${f##*/}" ] &&
mv "./${f##*/}" "$f"
done
이 솔루션에는 두 가지 가능한 문제가 있을 수 있습니다.
입력 파일 크기가 너무 커서 이렇게 한 번에 분할할 수 없습니다.
- 내 시스템에서는 입력이 수만 줄에 도달할 때까지 이것은 전혀 심각하게 고려할 가치가 없습니다.
파일 이름은
$destfile
현재 디렉터리에 있을 수 있지만아니요무슨 일이 있어도 감동받을 것입니다.- 이 솔루션은 두 입력 파일 비교를 완전히 포기하고
$destfile
현재 디렉터리에 있는 각 마지막 경로 이름 구성 요소의 존재 여부만 확인하므로, 의도하지 않게 일치할 수 있는 파일 이름은 고려해서는 안 됩니다.
- 이 솔루션은 두 입력 파일 비교를 완전히 포기하고
첫 번째 문제만 처리해야 하는 경우:
sed -ne"s|'|'"'\\&&|g' <"$destfile" \
-e "s|.*/\([^/].*\)|_mv './\1' '&'|p" |
sh -c '_mv(){ [ -e "$1" ]||[ -h "$1" ]&& mv "$@";};. /dev/fd/0'
그렇다면 마지막에 제거하고 다음을 사용할 sh
수 있습니다 .dash
. /dev/fd/0
sed ... | sh -cs '_mv(){ ...;}'
... dash
이상하게도 아무런 불만 없이 명령줄과 표준 입력 호출 옵션을 모두 처리하기 때문입니다. 이식성이 좋지는 않지만 . /dev/fd/0
이식성이 뛰어나기는 하지만 표준을 엄격하게 준수하지도 않습니다.
두 번째 질문이 질문인 경우:
export LC_ALL=C
sed -ne'\|/$|!s|.*/\(.*\)|\1/&|p' <"$destfile" |
sort -t/ -k1,1 - ./"$srcfile" | cut -d/ -f2- |
sed -e "\|/|!N;\|\n.*/|!d" \
-e "s|'|'"'\\&&|g' \
-e "s|\n|' '|;s|.*|mv './&'|" | sh
...모든 파일 이름이 . ./"$srcfile"
에 있는 한 두 개의 동일한 비교 중 짧은 항목이 맨 위에 표시되므로 첫 번째 필드만 중요하고 파일 이름이 각 경로 이름의 시작 부분에 추가되면 두 항목의 병합 작업이 수행됩니다. 파일은 다음 순서를 출력합니다."$destfile"
sort
"$destfile"
sort
$srcfile: no /
$destfile: match
$destfile: unique
$destfile: unique
...
$srcfile: no /
$destfile: match
$destfile: unique
...따라서 일치하지 않는 줄로 시작하는 줄 쌍에만 신경 쓰면 됩니다 /
.
답변3
while read i; do echo cp \""$i"\" \"$(grep "/$i$" dst.txt)\"; done < src.txt
그러면 의도한 내용이 인쇄됩니다. echo
실제로 파일을 복사하려면 삭제하세요 .
답변4
스크립트 줄은 스크립트를 생성하고 스크립트를 생성합니다.
이 예에서는 sed
on 에 대한 첫 번째 호출을 사용하여 파일 복사를 위한 쉘 스크립트를 생성하기 위해 실행될 src.txt
두 번째 스크립트를 생성 합니다.sed
dest.txt
다음 줄은 다음과 같습니다.
$ sed -n "$(sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt)" dest.txt #| sh -x
그리고 출력:
cp "file 3.jpg" "/dest/dir 1/file 3.jpg";
cp "file 1.jpg" "/dest/dir 2/file 1.jpg";
cp "file_2.html" "/dest/file_2.html";
#| sh
명령 끝에 있는 주석을 참고하십시오. 이렇게 하면 명령을 시도해보고 그 내용을 확인할 수 있으며, 제대로 작동하면 파이프의 주석 처리를 해제 sh
하고 실제로 파일을 복사할 수 있습니다.
내부 sed 명령은 src.txt를 기반으로 sed 스크립트를 작성합니다. 생성된 스크립트의 첫 번째 줄은 다음과 같습니다.
/\/file 1.jpg$/ { s/^/cp file 1.jpg /; p; }
작동 방식은 다음과 같습니다.
입력하다:
$ cat src.txt
file 1.jpg
file_2.html
file 3.jpg
$ cat dest.txt
/dest/dir 1/file 3.jpg
/dest/file4.txt
/dest/file 5.txt
/dest/dir 2/file 1.jpg
/dest/file_2.html
첫 번째 sed
전화. 이는 두 번째 호출에 의해 해석될 생성된 스크립트를 보여줍니다 sed
.
$ sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt
/\/file 1.jpg$/ { s/^/cp "file 1.jpg" "/; s/$/";/; p; }
/\/file_2.html$/ { s/^/cp "file_2.html" "/; s/$/";/; p; }
/\/file 3.jpg$/ { s/^/cp "file 3.jpg" "/; s/$/";/; p; }
첫 번째 명령의 출력을 sed
두 번째 호출에 전달되는 명령줄의 스크립트 로 사용하려면 셸 명령 대체를 사용합니다 sed
.
$ sed -n "$(sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt)" dest.txt
cp "file 3.jpg" "/dest/dir 1/file 3.jpg";
cp "file 1.jpg" "/dest/dir 2/file 1.jpg";
cp "file_2.html" "/dest/file_2.html";
sh -x
이제 xtrace 옵션( )을 사용하여 sed의 출력을 셸로 파이프합니다. 파일이 없어서 오류가 발생합니다.
$ sed -n "$(sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt)" dest.txt | sh -x
+ cp file 3.jpg /dest/dir 1/file 3.jpg
cp: cannot stat ‘file 3.jpg’: No such file or directory
+ cp file 1.jpg /dest/dir 2/file 1.jpg
cp: cannot stat ‘file 1.jpg’: No such file or directory
+ cp file_2.html /dest/file_2.html
cp: cannot stat ‘file_2.html’: No such file or directory