여러 파이프라인의 변수 범위

여러 파이프라인의 변수 범위

나는 다음을 수행하려고합니다.

find . -name "*.dat" | get the basename of file | move filename returned by first command to basename returned by second command

./mydir1/dir2/file1.dat구체적인 예를 들자면 이름을 로 바꾸고 싶습니다 file1.dat.

파이프로 할 수 있나요? 그렇다면 첫 번째 명령의 출력을 첫 번째 파이프의 변수에 저장하고 두 번째 파이프에서 어떻게 사용할 수 있습니까? "파이프라인"이라는 용어를 올바르게 사용했으면 좋겠습니다.

답변1

find 명령이 이 작업을 자체적으로 수행하므로 파이프가 필요하지 않습니다.

find . -name "*.dat" -exec mv -t . {} \;

.dat현재 디렉토리에 이미 있는 파일도 찾아서 이동하므로 이는 다소 비효율적입니다 .

답변2

파이프라인의 "수평적" 환경에는 실제로 영향을 미칠 수 없습니다. ... p_n | p_n+1 | p_n+2 ...파이프라인의 프로세스는 동일한 셸 해석기에 의해 생성되므로 환경 변수를 변경할 수 없습니다. 예를 들어 p_nechii p_m는 동일한 파이프라인에 있습니다.

파일 이름의 간단한 변환(정규식을 사용하여 수행할 수 있음)이 필요한 경우 다음을 수행하십시오.펄 예rename해야 할 것. 다음을 사용하여 xargs이스케이프 문제를 방지 하고 싶거나 필요할 수 있습니다.

find ... -print0 | xargs -0 rename "regexps"

NUL 바이트를 사용하여 파일 이름을 구분합니다(NUL과 백슬래시는 일반적으로 파일 이름에 표시되는 것이 금지된 유일한 문자입니다).

파일 이름이 제대로 작동한다면(따라서 정규 표현식에 사용되는 따옴표, 공백 및 구분 기호와 같은 특별한 "이상한" 문자 이스케이프가 필요하지 않다고 가정할 수 있음) 다음과 같은 빠르고 더러운 작업을 수행할 수도 있습니다.

find ... | sed -r "regexps" | sh -

이 경우 정규식은 유효한 명령 호출 mv(또는 필요한 작업을 수행하는 다른 명령)을 생성해야 합니다. 이는 다음과 같습니다.

"s|^.*$|mv -vi & &.old|"

이것은 다음과 같은 것을 생성합니다

...
mv -vi /etc/a2ps.cfg /etc/a2ps.cfg.old
mv -vi /etc/aclocal_dirlist /etc/aclocal_dirlist.old
...

간단한 정규 표현식이 충분히 강력하지 않은 경우그렇지 않으면 너무 많은 문제가 될 것입니다, 파일 이름을 처리하고 자체적으로 이름을 바꾸거나 이동하는 간단한 스크립트를 작성한 다음 find ( -exec또는 ) 또는 .find 를 통해 직접 -exec +호출하십시오 xargs.

마지막으로, 여러 파일의 복사본을 다른 디렉터리로 이동하려면 및 -t옵션을 사용하세요. GNU coreutils에는 소스와 전체 경로를 복사하는 옵션도 있습니다.cpmvcp--parents

답변3

가능한 가장 강력한 방법으로 실제 문제를 해결하려면 다음을 수행하십시오.

경고: 명령줄이 매우 깁니다.

find "${directory:-.}" -type f -name "*.dat" -exec sh -c 'for dat; do 
                                                                            if [[ -e $dat ]]; then
                                                                              base_fn=${dat%.*}$((++n)).dat
                                                                              base_fn=${dat##*/}
                                                                            else
                                                                              base_fn=${dat##*/}
                                                                            fi
                                                                            mv "$dat" "$base_fn"
                                                                           done' _ {} +

이것은 이식 가능합니다.POSIX이는 실제로 -exec ... {} +가장 일반적인 용도를 대체하도록 지정되었습니다 xargs. 내 생각엔 GNU에 특화된 것들이 mv -t좋은 것 같아요. 유일한 주의 사항은 GNU가 없으면 각 파일에 대해 새 프로세스를 생성 mv -t해야 한다는 것입니다.mv

반면에 디렉터리 구조를 평면화하면 동일한 기본 이름을 가진 파일이 손상될 수 있습니다. 내 접근 방식은 가장 극단적인 경우를 제외하고는 이를 피할 것입니다(ARG_MAX가 저장할 수 있는 것보다 더 많은 파일이 있는 경우,그리고두 번째 호출에서는 다음 sh위치에 있는 또 다른 중복된 기본 이름을 발견합니다.첫 번째전화하면 첫 번째 전화를 잃게 됩니다. )아 그렇군요. 이는 코딩하기 어려운 극단적인 경우입니다.

관련 정보