bash - O que {} significa?

1

Eu quero excluir arquivos, que têm tamanho = 0. Então, tentei:

find ./ -size 0 | xargs rm

Mas há um problema com os arquivos, cujos nomes começam com espaço. Eu encontrei isto:

find ./ -size 0 -exec rm -i {} \;

Funciona. Eu acho que meu caminho com xargs é muito sofisticado para isso.

O que significa {} \; ?

Você poderia me explicar? Meu inglês não é muito bom, então, por favor, escreva simplesmente.

    
por Adrian 03.05.2016 / 21:08

4 respostas

6

{} não tem absolutamente nenhum significado para bash , então é passado sem modificações como um argumento para o comando executado, aqui find .

Por outro lado, ; tem um significado específico para bash . É normalmente usado para separar comandos sequenciais quando eles estão na mesma linha de comando. Aqui, a barra invertida em \; é usada precisamente para impedir que o ponto-e-vírgula seja interpretado como um separador de comando por bash e, em seguida, permitir que ele seja passado como um parâmetro para o comando subjacente, find . A citação do ponto-e-vírgula, ou seja, ";" ou ';' , poderia ter sido uma maneira alternativa de não ser processada.

O comando:

find ./ -size 0 -exec rm -i {} \;

significa: encontre no diretório atual (note que / é inútil aqui, . não pode ser senão um diretório) qualquer coisa que tenha um tamanho de 0 e para cada objeto encontrado, execute o comando rm -i name , ou seja, solicitar interativamente para cada arquivo, se você quiser removê-lo. {} é substituído por cada nome de arquivo encontrado no comando executado. Uma característica interessante é que esse nome de arquivo é estritamente um único argumento, qualquer que seja o nome do arquivo (mesmo contendo espaços incorporados, tabulações, alimentações de linha e quaisquer caracteres). Este não seria o caso de xargs , a menos que hacks não portáteis sejam usados. O% final ; está lá para terminar a cláusula -exec . A razão pela qual seu fim precisa ser delimitado é que outras cláusulas find podem seguir o -exec , embora isso raramente seja feito.

Um problema com esse comando é que ele não ignorará arquivos não-simples, portanto, pode solicitar que o usuário exclua soquetes, dispositivos de bloco e de caractere, canais e diretórios. Ele sempre falhará com este último, mesmo se você responder sim.

Outro problema, embora não muito crítico aqui, é que rm será chamado para cada arquivo com tamanho zero. Se você substituir o -exec de /; a + , find otimizará a criação do subprocesso chamando apenas rm o número mínimo possível de vezes, muitas vezes apenas uma vez.

Aqui está como eu modificaria esse comando:

find . -type f -size 0 -exec rm -i {} +
    
por 03.05.2016 / 22:46
3

Ao usar find -exec , {} é expandido para cada resultado encontrado.

Por exemplo, se você tiver um diretório example contendo 3 arquivos a.txt , b.txt e c.txt , find example/ -exec rm -i {} \; será expandido para:

find example/ -exec rm -i example/a.txt \;
find example/ -exec rm -i example/b.txt \;
find example/ -exec rm -i example/c.txt \;

O \; no final é simples, um escape ; para indicar o fim do padrão exec. Caso contrário, seria interpretado pelo próprio shell.

    
por 03.05.2016 / 21:54
0

Em conjunto com a opção find do comando exec , a parte {} é substituída pelo nome dos arquivos encontrados quando o comando é executado. O \; é importante também, porque é isso que define o final do comando que está sendo executado

Por exemplo

find ~ -name \*.bak -exec -rm -f {} \;

excluiria todos os arquivos terminados em .bak em qualquer lugar no diretório pessoal do usuário ou nas pastas contidas nele. Executando rm -f em cada arquivo encontrado.

xargs usa linhas de entrada padrão, geralmente de um pipe, e forma a parte final dos argumentos quando executa o comando que você fornece

    
por 03.05.2016 / 21:52
0

Para analisar cada caso: -

xargs

O que esse programa faz é adicionar cada linha da entrada como um parâmetro a qualquer comando passado como seu próprio parâmetro e, em seguida, executar o comando resultante, portanto, se find listar três arquivos a , b e c no diretório atual que daria como saída:

./a
./b
./c

Se este for canalizado para xargs rm , este comando será executado:

rm ./a ./b ./c

No entanto, se find também encontrar um arquivo chamado " d e " , o comando executado se tornará:

rm ./a ./b ./c ./ d e 

Para lidar com isso, find fornece uma opção -print0 , que adiciona um caractere nulo ( xargs ) após cada arquivo, em vez da nova linha usual. Para informar a -0 que a entrada está neste formulário, adicione o parâmetro find -exec , então o comando:

find . ... -print0|xargs -0 rm

irá construir e executar o comando:

rm "./a" "./b" ."/c" "./ d e "

Isso funcionará em todos os nomes de arquivos, incluindo nomes contendo espaços em branco, tabulações e novas linhas.

\;

Quando essa opção é chamada, o que segue (até {} ) é executado para cada arquivo encontrado. Isso não é muito útil, a menos que haja algum meio de se referir ao arquivo encontrado no momento e é isso que o find faz. Pode ser chamado mais de uma vez na sequência de execução, por exemplo, para copiar uma seleção de arquivos em um diretório de backup:

find . ... -exec cp "{}" "/BackUp/{}" \;

Isso no exemplo find acima executaria por sua vez:

cp "./a" "/BackUp/./a"
cp "./b" "/BackUp/./b"
cp "./c" "/BackUp/./c"

Observe que, fora do uso no comando { , } e {} têm significados especiais no bash (vários comandos e listas de expansão), mas envolvem outros caracteres entre os colchetes: a string %code% é copiado literalmente, então não precisa escapar.

    
por 03.05.2016 / 21:52

Tags