Alguém tem um script de shell de modelo para fazer algo com ls
uma lista de nomes de diretório e percorrer cada um deles e fazer alguma coisa?
Estou planejando fazer ls -1d */
para obter a lista de nomes de diretório.
fonte
Alguém tem um script de shell de modelo para fazer algo com ls
uma lista de nomes de diretório e percorrer cada um deles e fazer alguma coisa?
Estou planejando fazer ls -1d */
para obter a lista de nomes de diretório.
Editado para não usar ls onde uma glob faria, como @ shawn-j-goff e outros sugeriram.
Basta usar um for..do..done
loop:
for f in *; do
echo "File -> $f"
done
Você pode substituir o *
com *.txt
ou qualquer outro globo que retorne uma lista (de arquivos, diretórios ou qualquer outra coisa), um comando que gera uma lista, por exemplo $(cat filelist.txt)
, ou substituí-lo por uma lista.
Dentro do do
loop, você apenas se refere à variável do loop com o prefixo do cifrão ( $f
no exemplo acima). Você pode echo
fazer ou fazer qualquer outra coisa que desejar.
Por exemplo, para renomear todos os .xml
arquivos no diretório atual para .txt
:
for x in *.xml; do
t=$(echo $x | sed 's/\.xml$/.txt/');
mv $x $t && echo "moved $x -> $t"
done
Ou melhor ainda, se você estiver usando o Bash, poderá usar as expansões de parâmetro do Bash em vez de gerar um subshell:
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
for
loops e uma armadilha típica de tentar analisar a saída dels
. @ DanielA.White, você pode considerar não aceitar esta resposta se ela não foi útil (ou é potencialmente enganosa), pois como você disse, você está atuando em diretórios. A resposta de Shawn J. Goff deve fornecer uma solução mais robusta e funcional para o seu problema.ls
saída , não deve ler a saída emfor
loop , deve usar em$()
vez de `` e Usar mais cotações ™ . Tenho certeza que o @CoverosGene teve um bom resultado, mas isso é simplesmente terrível.ls
éls -1 | while read line; do stuff; done
. Pelo menos esse não será quebrado por espaços em branco.mv -v
você não precisaecho "moved $x -> $t"
Usar a saída de
ls
para obter nomes de arquivos é uma má idéia . Isso pode levar a scripts com mau funcionamento e até perigosos. Isso ocorre porque um nome de arquivo pode conter qualquer caractere, exceto/
e onull
caráter, els
não usa qualquer um desses caracteres como delimitadores, por isso, se um nome de arquivo tem um espaço ou uma nova linha, você vai obter resultados inesperados.Existem duas maneiras muito boas de iterar sobre arquivos. Aqui, usei simplesmente
echo
para demonstrar fazer algo com o nome do arquivo; você pode usar qualquer coisa.A primeira é usar os recursos de globbing nativos do shell.
O shell se expande
*/
em argumentos separados que ofor
loop lê; mesmo se houver espaço, nova linha ou qualquer outro caractere estranho no nome do arquivo,for
cada nome completo será visto como uma unidade atômica; não está analisando a lista de forma alguma.Se você quiser entrar recursivamente em subdiretórios, isso não funcionará, a menos que o seu shell tenha alguns recursos de globbing estendidos (como
bash
o sglobstar
. Se o seu shell não tiver esses recursos, ou se você quiser garantir que seu script funcione em uma variedade de sistemas, a próxima opção é usarfind
.Aqui, o
find
comando chamaráecho
e passará um argumento para o nome do arquivo. Faz isso uma vez para cada arquivo encontrado. Como no exemplo anterior, não há análise de uma lista de nomes de arquivos; em vez disso, um fileneame é enviado completamente como argumento.A sintaxe do
-exec
argumento parece um pouco engraçada.find
pega o primeiro argumento depois-exec
e trata isso como o programa a ser executado, e todo argumento subsequente, leva como argumento a ser transmitido para esse programa. Existem dois argumentos especiais que-exec
precisam ser vistos. O primeiro é{}
; esse argumento é substituído por um nome de arquivofind
gerado pelas partes anteriores . O segundo é;
, que informa quefind
este é o fim da lista de argumentos a serem passados para o programa;find
precisa disso, porque você pode continuar com mais argumentos destinadosfind
e não destinados ao programa exec'd. A razão para\
isso é que o shell também trata;
especialmente - ele representa o fim de um comando; portanto, precisamos escapar dele para que o shell o dê como argumento, emfind
vez de consumi-lo por si mesmo; Outra maneira de fazer com que o shell não o trate especialmente é colocá-lo entre aspas:';'
funciona tão bem quanto\;
para esse propósito.fonte
find
. Há mágica que pode ser feita, e mesmo as limitações percebidas-exec
podem ser contornadas. A-print0
opção também é valiosa para uso comxargs
.Para arquivos com espaços, certifique-se de citar a variável como:
ou, você pode alterar a variável de ambiente separador de campo de entrada (IFS):
Finalmente, dependendo do que você está fazendo, você pode nem precisar dos ls:
fonte
\n
é insuficiente. Nunca é uma boa idéia recomendar a análise da saída dels
.Se você possui o GNU Parallel http://www.gnu.org/software/parallel/ instalado, você pode fazer isso:
Para renomear todos os .txt para .xml:
Assista ao vídeo de introdução do GNU Parallel para saber mais: http://www.youtube.com/watch?v=OpaiGYxkSuQ
fonte
Apenas para adicionar à resposta do CoverosGene, aqui está uma maneira de listar apenas os nomes de diretório:
fonte
Por que não definir o IFS para uma nova linha e capturar a saída de
ls
em uma matriz? Definir o IFS como nova linha deve resolver problemas com caracteres engraçados nos nomes de arquivo; O usols
pode ser bom porque possui um recurso de classificação interno.(Nos testes, eu estava tendo problemas para configurar o IFS,
\n
mas configurá-lo para o backspace da nova linha funciona, conforme sugerido em outro lugar aqui):Por exemplo (supondo que o
ls
padrão de pesquisa desejado seja passado$1
):Isso é especialmente útil no OS X, por exemplo, para capturar uma lista de arquivos classificados por data de criação (da mais antiga para a mais nova), o
ls
comando éls -t -U -r
.fonte
\n
é insuficiente. As únicas soluções válidas usam um loop for com expansão do nome do caminho oufind
.É assim que eu faço, mas provavelmente existem maneiras mais eficientes.
fonte
ls | while read i; do echo filename: $i; done