O comando dirname
remove o nome do arquivo do caminho completo
Estou tentando escrever um script que percorra todas as subpastas de um diretório para procurar um arquivo específico e copie um novo arquivo para as pastas que contêm esse arquivo.
Isso é o que eu tenho até agora:
#!/bin/sh
dir=/Documents
find "$dir" -name Sample.doc -printf "%p\n" | sort -nr | while read -r i; do
echo "$i"
done
Isso funciona para listar todos os arquivos Sample.doc
e suas pastas na pasta Documents
.
No entanto, não consigo encontrar uma maneira de extrair o caminho dessas pastas para copiar o novo arquivo para elas.
Qualquer ajuda seria apreciada.
O comando dirname
remove o nome do arquivo do caminho completo
Eu acho que você está quase lá. Você pode substituir %p
por %h
na expressão -printf
:
%h : Leading directories of file's name (all but the last element). If the file name contains no slashes (since it is in the current directory) the %h specifier expands to ".".
para que o comando seja algo como:
find "$dir" -name Sample.doc -printf "%h\n" | sort -nr | while read -r i; do cp SomeFile "$i"; done
a propósito, por que a parte sort
é necessária?
Usar %h
em vez disso %p
já foi sugerido em outra resposta, mas gostaria de adicionar algumas melhorias para tornar seu código mais robusto. Se, por exemplo, um diretório correspondente contiver um caractere de nova linha em seu nome, você, no melhor dos casos, acabará perdendo os diretórios e obtendo algumas mensagens de erro de cp . Na pior das hipóteses, você pode substituir arquivos em qualquer lugar do sistema.
Então, tente fazer assim:
find "$dir" -name Sample.doc -printf "%hfind "$dir" -name Sample.doc -printf "%h%pre%" | xargs --null -L1 cp SomeFile
" | xargs --null -L1 cp SomeFile
O zero ACSII é garantido para nunca aparecer em qualquer nome de arquivo, então, ao contrário de \n
, ele funciona como um separador confiável para passar os caminhos. --null
diz a xargs
para usar o
como um delimitador de entrada. Em seguida, executará o comando fornecido ( %code% ) uma vez por item passado pelo canal, enquanto anexando o respectivo item como argumento adicional. cp Somefile
No bash:
shopt -s nullglob globstar
for i in "$dir"/**/Sample.doc
do
cp 'new file' "$(dirname "$i")"/
done
Em peixes:
for i in $dir/**Sample.doc
cp 'new file' (dirname $i)/
end
Tags command-line bash linux