fundo
No Linux, você pode:
- Listar um grupo de arquivos com
ls Filename*
- Remova um grupo de arquivos com
rm Filename*
- Mova um grupo de arquivos com
mv Filename* /New/Directory
- Mas você não pode copiar um grupo de arquivos com:
cp Filename* *.bak
Alterar cp
comando do Linux para copiar o grupo de arquivos
Eu tenho um grupo de arquivos que gostaria de copiar sem digitar os nomes um por um e usar o cp
comando:
$ ls gmail-meta3*
gmail-meta3 gmail-meta3-REC-1558392194-26467821
gmail-meta3-LAB-1558392194-26467821 gmail-meta3-YAD-1558392194-26467821
Como posso usar algo como o antigo comando do DOS copy gmail-meta3* *.bak
?
Não quero digitar comando semelhante quatro vezes:
cp gmail-meta3-LAB-1558392194-26467821 gmail-meta3-LAB-1558392194-26467821.bak
Estou procurando um script / função / aplicativo que aceite parâmetros para o grupo de nome de arquivo antigo e novo e não algo com nomes de arquivos codificados. Por exemplo, um usuário pode digitar:
copy gmail-meta3* *.bak
ou eles podem digitar:
copy gmail-meta3* save-*
command-line
cp
ms-dos
WinEunuuchs2Unix
fonte
fonte
touch aa ab ba; mkdir bb; cp a* b*; ls *
*
para os nomes de arquivos de origem, mas não para os nomes de arquivos de destino. Como um curinga substituto (acho que##
foi sugerido, mas estou inclinado a%
), terá que ser usado para o destino. Eu acho que é isso que você está reforçando? Eu não esperava mudar ocp
comando. Basta criar um script de invólucro chamadocopy
que emulou (dentro do motivo) o comando de cópia do DOS.Respostas:
Aqui está um exemplo de um uso atípico de
sed
, aplicável a esta tarefa:Dessa forma, na verdade,
sed
não alterará os arquivos, porque não fornecemos nenhum comando''
, mas devido à opção,-i[suffix]
ele criará uma cópia de backup de cada arquivo. Encontrei essa abordagem quando estava pesquisando. Existe alguma maneira de criar uma cópia de backup de um arquivo, sem digitar seu nome duas vezes?fonte
$ time sed -i.bak '' gmail-meta3*
=real 0m0.069s
real 0m0.037s
. Se os arquivos apagados e executar uma segunda vez perto decp
velocidade:real 0m0.051s
.sed
é mais rápido quando os arquivos de destino já existem, mascp
é mais lento quando os arquivos de destino existem. Na verdade, eu libero caches e buffers, em vez desync
fazer grandes testes de temporização, mas não o fiz desta vez. Como isso pode se transformar em uma novela totalmente fora de questão, lamento compartilhar os resultados de meus testes :( É tarde demais para fingir que essa conversa nunca aconteceu? . Também não é um disco rígido, é um Samsung Pro 960 NVMe SSD em 4 canais.free
comando As gravações reais no dispositivo ocorrem no momento escolhido por um algoritmo que leva em consideração a idade do cache e a pressão da memória na máquina. Se você estiver tentando vários testes, as primeiras leituras do arquivo sairão do disco, mas as leituras subsequentes provavelmente ficarão sem memória (vejasync; echo 3 > /proc/sys/vm/drop_caches
).cp
comando, mas não posso dizer que haja alguma diferença significativa de desempenho .Você pode usar
find
:Isso encontrará no diretório atual
.
todos os arquivos com um nome correspondente ao padrão glob (lembre-se das aspas simples ao redor do padrão para evitar que o shell fique desfocado). Para cada arquivo encontrado, ele serácp
executado de name para name.bak. O \; no final, garante que cada arquivo seja executado individualmente, em vez de passar todos eles de uma vez. A profundidade máxima como 1 somente pesquisa o diretório atual em vez de recursar para baixo.fonte
find . -max-depth 1 -name '"$1"'' -exec cp "{}" "{}$2" \;
quando $ 1 for fonte e $ 2 for extensão?Você pode usar um
for
loop combash
. Normalmente, eu apenas digitava como uma linha, porque essa não é uma tarefa que realizo com frequência:No entanto, se você precisar dele como um script:
O uso é semelhante a
rename
. Testar:fonte
$ time for f in gmail-meta3* ; do cp -a "$f" "${f}.bak" ; done
=real 0m0.046s
0.046
segundos, o que significa 0 segundos para a percepção humana. Eu estava apenas tentando mostrar como estava testando as respostas postadas e transmitindo petiscos interessantes para os espectadores que olharam osed
comando acima. Ou, pelo menos, eu estava interessado em compararsed
comcp
.... #cp
é mais rápida que a solução comsed
embora. Portanto, é um motivo de comemoração :)-a
é um operador de teste não padrão. Por que não usar-e
? (2) "Não foi possível criar o diretório temporário". é uma mensagem de erro um tanto enganadora. (3) Por que não usar apenasmktemp -d
? (4) Você deve testar os status de saída. Por exemplo, você deve dizer! mkdir "$FOLDER" && echo "Unable to create temporary directory." && return 1
oumkdir "$FOLDER" || { echo "Unable to create temporary directory."; return 1;}
. Da mesma forma paracp
erename
(e talvez atépushd
, se você quiser ter cuidado). ... (continua)$@
; dizer"$@"
. (5b) Não há necessidade de usar{
e}
quando você faz referência a variáveis do jeito que está fazendo ("${FOLDER}"
,"${PATTERN}"
e"${file}"
); apenas faça"$FOLDER"
,"$PATTERN"
e"$file"
. (6) Isso pressupõe que os arquivos estejam no diretório atual.cps 's/$/.bak/' d/foo
copiarád/foo
parafoo.bak
no diretório atual, nãod/foo.bak
.O mais próximo que você provavelmente chegará do paradigma DOS é
mcp
(dommv
pacote):Se
zsh
estiver disponível, seuzmv
módulo contribuído talvez seja um pouco mais próximo:Eu evitaria
ls
independentemente - uma variante da sua própria resposta que seja segura para espaços em branco (incluindo novas linhas) seriaou talvez
fonte
mmv
é o pacote, mas nos comentários você diz que o comando é,mcp
mas depois no comando que você usa,mmv
que também é um comando nommv
pacote. Gosto da direção dosprintf
exemplos e, em um script polido, garantiria que $ 1 e $ 2 fossem passados. +1 para obter rolamento bola :)mcp
é apenas um sinônimo parammv -c
printf
comando que nunca usei realmente. Você está dizendoprintf '%s\0' "$1"*
que funcionaria segmail-meta3
fosse passado como parâmetro 1?cps gmail-meta3*
e depois escreverprintf '%s\0
"$ @" | enquanto ... `na função. Ou simplesmente usarfor f; do cp -- "$f" "$f.bak"; done
(como resposta de xiota , mas como uma função)zmv
você pode usar o modo "substituição de curinga", que eu acho um pouco mais fácil dezmv -W -C 'gmail-meta3*' '*.bak'
única solução rsync
Se você quiser apenas fazer backup de seus arquivos, poderá copiá-los para um novo diretório
rsync /path/to/dir/Filename* /path/to/backupdirectory
Isso copiará os
Filename
arquivos de/path/to/dir/
para/path/to/backupdirectory
.rsync + nome do arquivo
Se você deseja que seus arquivos de backup tenham um sufixo, as coisas ficam
rsync
...rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak
Isso sobrescreveria os arquivos existentes ... pelos arquivos existentes (
-I
), mas apenas se eles fossem (-u
) mais recentes (que não são) e criando um backup, com um sufixo.Você também pode fazer isso no mesmo diretório. Mas é melhor excluir os backups existentes.
rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak --exclude '*.bak'
fonte
rsycnc
que eu votei, mas um método mais simples seriacp Filename* /path/to/backup/dir
porque os arquivos não precisariam de um*.bak
uniquificador se estivessem em um diretório separado.Este deve fazer conforme solicitado:
Uso:
Eu escolhi
?
porque#
deve ser citado quando é o primeiro caractere do padrão, caso contrário, é reconhecido como o início de um comentário.Teste:
Algumas versões anteriores do script para adicionar um sufixo:
Semelhante à resposta do @ WinEunuuchs2Unix, mas acho mais flexível e não analisa
ls
:Coloque isso no seu
.bashrc
.Uso:
Alternativa, com o sufixo como último argumento ( via e via ):
Uso:
fonte
copy gmail-meta3* old-meta3*
. Em minha resposta eu não conseguia descobrir como chegar*
ao nome do destino como a minha pergunta solicitada ...*
é interpretado pelo shell, portanto a função não o saberá. Você precisaria de outro caractere ou citá-lo e substituí-lo pelo nome do arquivo original na função.#
poderia ser usado como um curinga substituto para*
? Então você pode digitarcopy filenames# save-#
. Eu acho que você gostaria que o caractere curinga fosse o mesmo para origem e destino.Eu escrevi essa frase no meu
~/.bashrc
. Respostas muito melhoresfind
podem ser postadas, suponho. Respostas ainda melhores podem ser escritas em C. Espero que essas perguntas e respostas façam a bola rolar para melhores respostas:for f in "$1"*; do
:$1
é ogmail-meta3
parâmetro ef
é a lista de arquivos correspondentes. Combinado isso significa para o gmail-meta3, gmail-meta3-LAB-9999, etc., faça o seguinte[[ ! "$f" == *"$2" ]] &&
:$f
é o mesmo quef
acima.$2
é o.bak
parâmetro passado. Combinado isso significa que, se o nome do arquivo não terminar.bak
(porque não queremos copiar.bak
e criar.bak.bak
), faça o seguintecp -a "$f" "$f$2";
copiar gmail-meta3 para gmail-meta3.bak, etc.done
: volte e pegue o próximo nome de arquivo nagmail-meta3
lista *.cps gmail-meta3 .bak
Saída de amostraUsando a pergunta como exemplo, veja como ela fica em ação:
Nota: Isso usa o
-a
sinalizador com ocp
comando para preservar os carimbos de data e hora e oferecer uma melhor compreensão dos backups de arquivos.Observe como as cópias dos arquivos têm exatamente a mesma data e hora dos originais. Se o
-a
parâmetro fosse omitido, eles receberiam a data e a hora atuais e não pareceriam um backup verdadeiro, exceto que o tamanho do arquivo seria o mesmo.fonte
ls
find
, presumo que esteja ciente dos perigos da análisels
? Mas no seu caso, nenhum dos dois é necessário: apenas façafor file in "$1"*; do copy -a "$file" "$file$2"; done
- isso é completamente seguro e muito mais simples do que qualquer tipo de indireto vials
oufind
e umwhile
loop.Outro método para atingir seus requisitos é copiar os arquivos para um diretório temporário e usar o
rename
comando para renomeá-los.Se você precisar dele como um script, poderá usá-lo assim
E você pode usá-lo assim:
Isto é um exemplo
fonte