Escopo variável em vários canais

1

Eu estava tentando fazer algo a seguir,

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

Para dar um exemplo concreto, quero que ./mydir1/dir2/file1.dat seja renomeado como file1.dat .

Posso fazer isso usando pipes. Se sim, como armazenar a saída do primeiro comando em uma variável no primeiro canal e usá-la no segundo canal. Espero que eu esteja usando o termo pipe corretamente.

    
por Dilawar 21.05.2013 / 10:02

3 respostas

2

Você não precisa de pipes para que o comando find seja capaz de fazer isso:

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

Observe que isso é um pouco ineficiente, pois os arquivos .dat já existentes no diretório atual também são encontrados e movidos.

    
por 21.05.2013 / 10:08
2

Você não pode realmente influenciar o ambiente "horizontalmente" no pipe - os processos em um ... p_n | p_n+1 | p_n+2 ... pipe são gerados pelo mesmo interpretador de shell, portanto não há como alterar a variável de ambiente de p_n de p_m , echii está no mesmo pipeline.

Se você só precisa fazer uma transformação simples dos nomes de arquivos, o que pode ser conseguido com expressões regulares, então o Perl exemplo rename deve fazer. Você pode querer / precisar usar xargs para evitar problemas com escape

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

que delimita os nomes dos arquivos com bytes NUL (NUL e contrabarra são os únicos caracteres que geralmente são proibidos de aparecer em um nome de arquivo).

Se os nomes dos seus arquivos forem bem comportados (e, portanto, você pode supor que você não precisa de nenhum escape especial de caracteres "estranhos" como aspas, espaços e separadores usados nos regexps), você também pode fazer algo rápido e sujo como:

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

Nesse caso, o regexps precisa criar um comando válido chamando mv (ou qualquer outra coisa que execute a ação desejada) - pode parecer:

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

que produz algo como

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

Se a expressão regular simples não for poderosa ou for muito pesada , apenas escreva um script simples que processe nomes de arquivos e renomeie / mova-se e chame-o diretamente de find ( -exec ou -exec + ) ou através de xargs .

Por fim, se você quiser apenas mover o grupo de arquivos para outro diretório, use a opção -t de cp e mv . cp no GNU coreutils também tem a opção --parents , que copia a fonte com seu caminho completo.

    
por 21.05.2013 / 14:21
0

Em um esforço para resolver o problema real da maneira mais robusta possível:

AVISO: linha de comando muito longa.

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' _ {} +

Isto é portátil; POSIX na verdade especifica este -exec ... {} + como um substituto para o uso mais comum de xargs . O mv -t específico do GNU é bom ter por aí, suponho. O único problema a notar é que, sem o mv -t do GNU, você precisa gerar um novo processo mv para cada arquivo.

Por outro lado, achatar uma estrutura de diretórios corre o risco de destruir arquivos que tenham o mesmo nome de base. Meu método evitará isso, exceto na situação mais extrema (se você tiver mais arquivos do que você pode ajustar em ARG_MAX, e na segunda chamada de sh , você executa em outro nome de base duplicado que estava no primeiro invocação, então você vai perder o primeiro.) oh bem. um caso de canto tão horrível para codificar em volta.

    
por 23.07.2013 / 19:19