다음 코드를 사용하여 마지막 파일을 생략하고 나머지 파일을 대상 폴더에 복사하려고 합니다.
ls -Art | tail -n 1 | xargs -I% cp !(%) ~/test_dst/folder1
처음 두 파이프는 최신 파일의 이름을 가져오고 이것은 xargs로 파이프되어 이를 cp 명령에 추가합니다. 여기서 extglob의 ! 다른 모든 것을 복사하려면 와일드카드를 사용하세요. 하지만 문제는 이것이 모든 파일을 복사한다는 것입니다! 나는 이 인쇄의 첫 번째 부분(set -x가 켜져 있음)이 무엇인지 확인하여 디버깅을 시도했습니다.
> ~/test_src/folder1$ ls -Art | tail -n 1
+ tail -n 1
+ ls --color=auto -Art
file4
성공! 이것은 실제 올바른 파일입니다! 그런 다음 와일드카드를 사용하여 인쇄해 보았습니다.
> ~/test_src/folder1$ ls -Art | tail -n 1 | xargs -I% echo !(%)
+ tail -n 1
+ ls --color=auto -Art
+ xargs -I% echo file1 file2 file3 file4
file1 file2 file3 file4
그리고 생략된 파일이 포함되어 있나요?? 명령 자체를 하드코딩하려고 했는데 실제로 제대로 작동한다는 사실을 알고 계시나요?
> ~/test_src/folder1$ echo !(file4)
+ echo file1 file2 file3
file1 file2 file3
내가 도대체 뭘 잘못하고있는 겁니까? 이것은 기본적으로 쉘 스크립트에 대한 나의 첫 번째 시도이고 그것은 나를 미치게 만듭니다. 어떤 조언이라도 대단히 감사하겠습니다. 나는 이 특정 방법을 디버그하는 것을 선호하지만(이것은 내가 생각한 방식일 뿐입니다), 이 작업을 수행하는 데 대한 제안이나 대체 방법에 대해 분명히 열려 있습니다. 감사합니다!
답변1
예, 작동하지 않을 것입니다. 결합하려는 두 기능이 잘못된 순서로 해석됩니다.
Extglobs는 셸(명령 해석기)의 기능이며 "trace" 출력에서 알 수 있듯이 bash에 의해 확장됩니다.~ 전에'xargs' 명령이 실제로 실행됩니다.
extglob 또는 실제로 모든 glob이 있는 그대로 xargs(또는 'echo' 또는 'cp')에 전달되면 이를 어떻게 해야 할지 알 수 없습니다. 예를 들어 'cp'는 "!(%)" 또는 "!(file1)"이 문자 그대로 복사할 파일 이름이라고 생각합니다.
반면에 xargs는~ 아니다쉘의 일부 – 다른 프로그램과 마찬가지로 독립형 프로그램이며 bash는 "%"의 의미를 모르거나 xargs에 다른 명령을 전달한다는 사실도 모릅니다.
따라서 !(%)
extglob이 확장될 때 확장만 됩니다.한 번전체 명령에 대해 – 각 xargs 입력에 대해 한 번이 아니라 %
Bash가 명령에서 보는 리터럴에 대해 한 번만. 물론 이는 다음과 같은 결과를 낳습니다.이름이 지정되지 않은 모든 파일%
.
이를 수행하는 한 가지 방법은 xargs를 쉘 자체 확장으로 바꾸는 것입니다. xargs와 달리 쉘 변수는 확장됩니다.~ 전에extglobs, 따라서 변수에 파일 이름이 있다면...
except_file=$(ls -Art | tail -n 1)
...extglob에서 사용할 수 있습니다.
cp !("$except_file") ~/test_dst/folder1
(두 개를 합쳐서 로 만들 수도 있습니다 cp !("$(ls...)") ~/...
.)
반대로 xargs를 유지하면서 extglob을 제거하는 것도 가능합니다. 마지막 파일만 가져온 다음 tail
다른 모든 파일을 가져오기 위해 추가 단계가 필요한 대신, 직접 가져올 수 있습니다.제외한 모든 것다음을 사용하는 마지막 파일 head
('head'와 'tail' 모두에 대한 음수 매개변수는 "마지막 N 제외"를 의미함):
ls -Art | head -n -1 | xargs -I% cp % ~/test_dst/folder1
또는 xargs가 모든 파일에 대해 한 번에 하나를 호출하는 작업을 수행하도록 하려면 cp
시스템에 다음 cp -t <target>
옵션이 있는 GNU Coreutils가 있다고 가정합니다.
ls -Art | head -n -1 | xargs -d '\n' cp -t ~/test_dst/folder1
참고 사항: Linux의 파일 이름에는 줄 바꿈이 포함될 수 있습니다. 위의 예 중 다수에서는 실제로 그렇게 하면 안 되기 때문에 그러한 파일 이름이 없다고 가정합니다.~이다알 수 없는 시스템에 배포할 스크립트를 작성할 때 고려해야 할 사항이며 "방어적" 프로그래밍에는 일반적으로 개행으로 구분된 목록 대신 null로 구분된 목록과 find ... -print0
같은 도구가 포함됩니다 . xargs -0
(셸 와일드카드는 일반적으로 문제를 잘 처리합니다.)