Digamos se eu escrevi um programa com a seguinte linha:
int main(int argc, char** argv)
Agora ele sabe quais argumentos da linha de comando são passados para ele, verificando o conteúdo de argv
.
O programa pode detectar quantos espaços entre argumentos? Como quando eu digito estes no bash:
ibug@linux:~ $ ./myprog aaa bbb
ibug@linux:~ $ ./myprog aaa bbb
O ambiente é um Linux moderno (como o Ubuntu 16.04), mas suponho que a resposta deva se aplicar a qualquer sistema compatível com POSIX.
Respostas:
Não é significativo falar de "espaços entre argumentos"; esse é um conceito de concha.
O trabalho de um shell é pegar linhas inteiras de entrada e transformá-las em matrizes de argumentos para iniciar os comandos. Isso pode envolver a análise de seqüências de caracteres entre aspas, a expansão de variáveis, curingas de arquivos e expressões de til e muito mais. O comando é iniciado com uma
exec
chamada de sistema padrão , que aceita um vetor de cadeias.Existem outras maneiras de criar um vetor de strings. Muitos programas bifurcam e executam seus próprios subprocessos com invocações de comandos predeterminadas - nesse caso, nunca existe uma "linha de comando". Da mesma forma, um shell gráfico (da área de trabalho) pode iniciar um processo quando um usuário arrasta um ícone de arquivo e o solta em um widget de comando - novamente, não há linha de texto para ter caracteres "entre" argumentos.
No que diz respeito ao comando invocado, o que ocorre em um shell ou outro processo pai / precursor é privado e oculto - só vemos a matriz de strings que o padrão C especifica que
main()
pode aceitar.fonte
tar cf texts.tar *.txt
, o programa tar recebe dois argumentos e precisa expandir o segundo (*.txt
). Muitas pessoas não percebem como realmente funciona até começarem a escrever seus próprios scripts / programas que lidam com argumentos.Em geral, não. A análise da linha de comando é feita pelo shell, que não disponibiliza a linha não analisada para o programa chamado. De fato, seu programa pode ser executado a partir de outro programa que criou o argumento não analisando uma string, mas construindo uma matriz de argumentos programaticamente.
fonte
execve(2)
.Não, isso não é possível, a menos que os espaços façam parte de um argumento.
O comando acessa os argumentos individuais de uma matriz (de uma forma ou de outra, dependendo da linguagem de programação) e a linha de comando real pode ser salva em um arquivo de histórico (se digitado em um prompt interativo em um shell que possui arquivos de histórico), mas é nunca passou para o comando de qualquer forma.
Todos os comandos no Unix são executados no final por uma das
exec()
famílias de funções. Estes levam o nome do comando e uma lista ou matriz de argumentos. Nenhum deles usa uma linha de comando conforme digitado no prompt do shell. Asystem()
função funciona, mas seu argumento de seqüência de caracteres é posteriormente executado porexecve()
, que, novamente, recebe uma matriz de argumentos em vez de uma linha de comando.fonte
hello
eworld
é literalmente espaços entre os dois argumentos.hello
e literalmenteworld
está fornecendo o segundo dos três argumentos.Em geral, não é possível, como várias outras respostas explicadas.
No entanto, os shells do Unix são programas comuns (e eles estão interpretando a linha de comando e dando uma olhada nela, ou seja, expandindo o comando antes de fazê
fork
-execve
lo). Veja esta explicação sobrebash
operações shell . Você pode escrever seu próprio shell (ou corrigir algum shell de software livre existente , por exemplo, GNU bash ) e usá-lo como seu shell (ou mesmo como seu shell de login, consulte passwd (5) & shells (5) ).Por exemplo, você pode ter seu próprio programa de shell colocando a linha de comando completa em alguma variável de ambiente (imagine
MY_COMMAND_LINE
por exemplo) - ou usar qualquer outro tipo de comunicação entre processos para transmitir a linha de comando do shell para o processo filho-.Não entendo por que você gostaria de fazer isso, mas você pode codificar um shell se comportando dessa maneira (mas eu recomendo não fazê-lo).
BTW, um programa pode ser iniciado por algum programa que não é um shell (mas que bifurca (2) e depois executa (2) , ou apenas um
execve
para iniciar um programa em seu processo atual). Nesse caso, não há linha de comando e seu programa pode ser iniciado sem um comando ...Observe que você pode ter algum sistema Linux (especializado) sem nenhum shell instalado. Isso é estranho e incomum, mas possível. Você precisará escrever um programa init especializado , iniciando outros programas conforme necessário - sem usar nenhum shell, mas fazendo
fork
&execve
chamadas de sistema.Leia também Sistemas operacionais: Três partes fáceis e não se esqueça que
execve
praticamente sempre é uma chamada do sistema (no Linux, elas estão listadas em syscalls (2) , consulte também a introdução (2) ) que reinicializam o espaço de endereço virtual (e outras coisas) do processo .fonte
argv[0]
para o nome do programa e os elementos restantes para os argumentos, são especificações POSIX e não podem ser alterados. Um ambiente de tempo de execução pode especificarargv[-1]
para a linha de comando, presumo ...execve
documentação com mais cuidado . Você não pode usarargv[-1]
, é um comportamento indefinido para usá-lo.execvepluscmd
com um parâmetro extra (ou convenção argv), o syscall constrói um vetor de argumento para main que contém um ponteiro para a linha de comando antes do ponteiro para o nome do programa e depois passa o endereço do ponteiro para o nome do programa comoargv
ao chamar o programamain
...sh
. Então não é novidade.Você sempre pode dizer ao seu shell para dizer aos aplicativos que código de shell leva à sua execução. Por exemplo, com
zsh
, passando essas informações na$SHELL_CODE
variável de ambiente usando opreexec()
gancho (printenv
usado como exemplo, você usariagetenv("SHELL_CODE")
em seu programa):Todos aqueles seriam executados
printenv
como:Permitindo
printenv
recuperar o código zsh que leva à execuçãoprintenv
com esses argumentos. O que você gostaria de fazer com essas informações não está claro para mim.Com
bash
, o recurso mais próximozsh
'spreexec()
estaria usando seu$BASH_COMMAND
em umaDEBUG
armadilha, mas nota quebash
faz algum nível de reescrever em que (e em refatora particulares alguns dos espaços em branco usado como delimitador) e que é aplicado a cada (bem, alguns) de comando executar, não toda a linha de comando, conforme inserido no prompt (consulte também afunctrace
opção).Veja como alguns dos espaços delimitadores na sintaxe da linguagem shell foram compactados em 1 e como nem toda a linha de comando nem sempre é passada para o comando. Então provavelmente não é útil no seu caso.
Observe que eu não recomendaria esse tipo de coisa, pois você está potencialmente vazando informações confidenciais para todos os comandos, como em:
vazaria esse segredo para ambos
wc
euntrustedcmd
.Claro, você poderia fazer esse tipo de coisa para outros idiomas além do shell. Por exemplo, em C, você pode usar algumas macros que exportam o código C que executa um comando para o ambiente:
Exemplo:
Veja como alguns espaços foram condensados pelo pré-processador C, como no caso do bash. Na maioria dos idiomas, se não em todos os idiomas, a quantidade de espaço usada nos delimitadores não faz diferença; portanto, não é de surpreender que o compilador / intérprete tenha alguma liberdade com eles aqui.
fonte
BASH_COMMAND
não continha os argumentos de separação de espaço em branco originais, portanto isso não era utilizável para a solicitação literal do OP. Esta resposta inclui alguma demonstração de qualquer maneira para esse caso de uso específico?Vou apenas adicionar o que está faltando nas outras respostas.
Não
Veja outras respostas
Talvez, mais ou menos
Não há nada que possa ser feito no programa, mas há algo que pode ser feito no shell quando você executa o programa.
Você precisa usar aspas. Então, ao invés de
você precisa fazer um desses
Isso passará um único argumento para o programa, com todos os espaços. Há uma diferença entre os dois, o segundo é literal, exatamente a string que aparece (exceto que
'
deve ser digitada como\'
). O primeiro interpretará alguns caracteres, mas será dividido em vários argumentos. Veja shell citando para mais informações. Portanto, não há necessidade de reescrever o shell, os designers do shell já pensaram nisso. No entanto, como agora é um argumento, você precisará fazer mais alterações no programa.opção 2
Passe os dados via stdin. Essa é a maneira normal de obter grandes quantidades de dados em um comando. por exemplo
ou
./myprog
Tell me what you want to tell me:
aaaa bbb
ctrl-d
(Itálico são resultados do programa)
fonte
./myprog␣"␣␣␣␣␣aaa␣␣␣␣␣␣bbb"
executa (geralmente em um processo filho) o arquivo armazenado no./myprog
e passa dois argumentos:./myprog
e␣␣␣␣␣aaa␣␣␣␣␣␣bbb
(argv[0]
eargc[1]
,argc
sendo 2) e como no OP de, o espaço que separa estes dois argumentos não é passado de qualquer maneira paramyprog
.