Execute no nome da base de um comando find

3

Suponha que eu tenha uma estrutura de diretórios como segue

test
test/a
test/b

Agora eu quero executar um comando, tal que na pasta . eu possa executar um comando no nome de base dos arquivos a e b .

Então, basicamente, eu quero algo assim, que eu ingenuamente tentei

find test -type f -exec touch 'basename {}' \;

Apenas isso não resulta em arquivos vazios a e b no diretório pai. Suponha que meu comando de toque só possa aceitar um único argumento.

Isso resultará em uma estrutura de diretórios como essa

a
b
test
test/a
test/b

Eu sei como fazer isso em um script bash, mas estou interessado em solução de comando único.

    
por Bernhard 30.05.2012 / 08:47

5 respostas

1

Experimente a opção execdir para find : executa o comando especificado no diretório do arquivo, usando apenas seu nome de base como argumento

Pelo que eu sei, você quer criar "a" e "b" no diretório "main". Podemos fazer isso combinando $PWD e a opção -execdir . Dê uma olhada na solução abaixo. (As partes && find … ls são apenas para saída, assim você pode ver os efeitos. Você vai querer usar o comando antes do && .)

Primeiro, eu configuro o ambiente de teste:

-----[ 15:40:17 ] (!6293) [ :-) ] janmoesen@mail ~/stack 
$ mkdir test && touch test/{a,b} && find . -exec ls -dalF {} +
drwxr-xr-x 3 janmoesen janmoesen 4096 2012-05-31 15:40 ./
drwxr-xr-x 2 janmoesen janmoesen 4096 2012-05-31 15:40 ./test/
-rw-r--r-- 1 janmoesen janmoesen    0 2012-05-31 15:40 ./test/a
-rw-r--r-- 1 janmoesen janmoesen    0 2012-05-31 15:40 ./test/b

Isso é o que acontece quando você usa um simples -exec - os arquivos originais são tocados:

-----[ 15:40:30 ] (!6294) [ :-) ] janmoesen@mail ~/stack 
$ find test -type f -exec touch {} \; && find . -exec ls -dalF {} +
drwxr-xr-x 3 janmoesen janmoesen 4096 2012-05-31 15:40 ./
drwxr-xr-x 2 janmoesen janmoesen 4096 2012-05-31 15:40 ./test/
-rw-r--r-- 1 janmoesen janmoesen    0 2012-05-31 15:40 ./test/a
-rw-r--r-- 1 janmoesen janmoesen    0 2012-05-31 15:40 ./test/b

No entanto, se combinarmos $PWD com o argumento placeholder {} e usar -execdir , conseguiremos o que (eu acho) você deseja:

-----[ 15:40:57 ] (!6295) [ :-) ] janmoesen@mail ~/stack 
$ find test -type f -execdir touch "$PWD/{}" \; && find . -exec ls -dalF {} +
drwxr-xr-x 3 janmoesen janmoesen 4096 2012-05-31 15:41 ./
-rw-r--r-- 1 janmoesen janmoesen    0 2012-05-31 15:41 ./a
-rw-r--r-- 1 janmoesen janmoesen    0 2012-05-31 15:41 ./b
drwxr-xr-x 2 janmoesen janmoesen 4096 2012-05-31 15:40 ./test/
-rw-r--r-- 1 janmoesen janmoesen    0 2012-05-31 15:40 ./test/a
-rw-r--r-- 1 janmoesen janmoesen    0 2012-05-31 15:40 ./test/b
    
por 31.05.2012 / 15:46
4

Execute bash.

find ... -exec bash -c 'touch "${1##*/}"' btouch {} \;

Aqui ${1##*/} significa: remova a correspondência mais longa do segundo argumento que termina com / , mantendo assim tudo após o último / .

btouch pode ser qualquer nome fictício, para aparecer corretamente na lista de processos ativos ( ps )

    
por 30.05.2012 / 08:58
3

Tente isso por sua conta e risco:

find test -type f -exec echo touch \"\$\(basename "'{}'"\)\" \; | bash

Testado com nomes de arquivos com espaços.

    
por 31.05.2012 / 19:20
1

Que tal isso?

$ touch $(find test -type f -exec basename {} \;)
    
por 30.05.2012 / 08:58
1

Invoque um shell para fazer um pouco de processamento de string no caminho. Você pode usar a construção de manipulação% string ${VARIABLE##PATTERN} para remover um prefixo correspondente a PATTERN de VARIABLE - o padrão */ retira os nomes dos diretórios principais.

find test -type f -exec sh -c 'for x; do touch "${x##*/}"; done' _ {} +

Um método alternativo com o GNU find é fazer com que ele seja alterado para os subdiretórios. Invoque um shell para voltar ao diretório original.

find test -type f -execdir sh -c 'cd "$0" && touch -- "$@"' "$PWD" {} +

Ou elimine find e use zsh. Especificamente, adicione o t modificador de histórico como um Qualificador de globo .

touch test/**/*(:t)
    
por 31.05.2012 / 02:15