Eu tenho um programa que espera argumentos na seguinte sintaxe:
prog [-f filename | -g filename1 filename2] ...
Cada nome de arquivo deve ser prefixado com o -f
sinalizador. Por exemplo, as invocações a seguir são válidas de prog
:
prog -f a.txt -g b.txt c.txt -f d.txt
prog -g a.txt b.txt -g c.txt d.txt
prog -f a.txt -f b.txt -f c.txt
…mas os seguintes não são:
prog -f a.txt b.txt
prog -f a.txt -g b.txt
prog a.txt
No meu caso, eu só me importo com a -f
opção.
Eu tenho muitos arquivos em um diretório, todos terminando em .txt
. Eles se parecem com isso:
important-files/
├── a.txt
├── b.txt
├── c.txt
├── d.txt
└── filename with spaces.txt
Eu gostaria de evitar a necessidade de listar todos os arquivos, um por um. Normalmente, eu usaria um glob direto para isso:
$ prog important-files/*.txt
Mas isso não funciona, pois produz a seguinte invocação inválida:
$ prog important-files/a.txt important-files/b.txt important-files/c.txt important-files/d.txt 'important-files/filename with spaces.txt'
…quando eu realmente quero esta invocação:
$ prog -f important-files/a.txt -f important-files/b.txt -f important-files/c.txt -f important-files/d.txt -f 'important-files/filename with spaces.txt'
…uma vez que cada nome de arquivo deve ser prefixado com -f
para prog
entender, eles não devem ser interpretados como -g
.
Qual é a maneira mais curta de usar um glob e prefixar cada um dos arquivos para os quais ele se expande com um sinalizador?
Usando
printf
e umaxargs
entrada delimitada por nul de suporte:printf
faz um loop da string de formato sobre os argumentos, portanto, para cada nome de arquivo na expansão do glob, ele será impresso-f
e o nome do arquivo separado pelo caractere nulo.xargs
em seguida, lê isso e o converte em argumentos paraprog
. O--
necessário, pois algumas implementações deprintf
têm problemas com uma liderança-
na string de formato. Como alternativa, o-
pode ser substituído por\055
, que é padrão.Mesmo princípio da resposta de Rakesh , mas usando a expansão curinga diretamente.
zsh
agora tem umP
qualificador glob para isso .Para versões mais antigas, você sempre pode usar:
$^f
habilita arcexpandparam
opção de expansão de$f
, onde os arrays são expandidos em um estilo semelhante ao dorc
shell.Em
rc
(ouzsh -o rcexpandparam
):É expandido para
prog -fa.txt -fb.txt
, um pouco como se você tivesse escrito em csh (ou outros shells que suportam expansão de chaves):prog -f{a.txt,b.txt}
.(observe que é diferente
*.txt(P:-f:)
porque o nome do arquivo é colado à opção-ffile.txt
em vez de passar dois argumentos-f
file.txt
. Muitos comandos, incluindo todos aqueles que usam agetopt()
API padrão para analisar as opções, suportam a passagem de argumentos para as opções nos dois sentidos).fish
também expande arrays assim:Em
bash
, você pode emulá-lo com:Com
ksh93
:Para
-f
e osfile.txt
s correspondentes serem passados como argumentos separados, outra opção comzsh
o uso de seu operador de compactação de matriz:Você pode estender isso para sua
-g
opção. Supondo que haja um número par detxt
arquivos:Passaria
-g
opções com dois arquivos por vez. Semelhante ao que você obteria com:Com o bash, tente:
Observe que isso funcionará não apenas com nomes de arquivo que contenham espaços em branco, mas também com nomes de arquivo que contenham aspas simples ou duplas ou mesmo novas linhas.
Fácil uso interativo
Para facilitar o uso interativo, defina uma função:
Esta função pode ser utilizada da seguinte forma:
Para tornar a definição de função permanente, coloque-a em seu
~/.bashrc
arquivo.Como thrig já mencionou em um comentário:
Isso usa o qualificador glob
P
que precede uma palavra separada para cada correspondência glob. Como quase todos os qualificadores glob do zsh, o bash não tem nada semelhante.Se você deseja concluir para
prog
, executezsh
interativamente e digiteprog *.txt(P:-f:)
. Na primeira vez que você executar o zsh interativamente, ele solicitará que você defina uma configuração. Se você não se importa com o zsh, escolha a opção de deixar em branco.zshrc
(mas perderá alguns recursos do zsh que precisam ser ativados explicitamente) ou escolha1
e percorra os menus para ativar os padrões recomendados.Um. método para fazer isso é com o GNU find/xargs duo:
POSIXLY, você sempre pode definir uma função como: