@MestreLion Muitas vezes as pessoas leem uma pergunta para encontrar uma solução para uma variação de um problema. Este começa com a premissa falsa que cutsuporta algo que não suporta. Mas achei útil, pois força o leitor a considerar um código mais fácil de seguir. Eu queria um rápido, muito simples de usar cut, sem necessidade de utilizar várias sintaxes para awk, grep, sed, etc. A revcoisa fez o truque; muito elegante e algo que eu nunca considerei (mesmo que desajeitado para outras situações). Também gostei de ler as outras abordagens das outras respostas.
Beejor 23/08/16
3
Vim aqui um problema da vida real: quero encontrar todas as extensões de arquivo diferentes em uma árvore de origem, para atualizar um arquivo .gitattributes. Assim find | cut -d. -f<last>é a inclinação natural
studog
Respostas:
680
Você pode tentar algo como isto:
echo 'maps.google.com'| rev | cut -d'.'-f 1| rev
Explicação
rev reverte "maps.google.com" para ser moc.elgoog.spam
cut usa ponto (ou seja, '.') como delimitador e escolhe o primeiro campo, que é moc
Não está usando apenas cutmas está sem sedou awk.Então, o que OP pensa?
Jayesh Bhoi
7
A @tom OP fez mais perguntas do que apenas isso nas últimas horas. Com base em nossas interações com o OP, sabemos que awk / sed / etc. não são permitidos em sua lição de casa, mas uma referência a rev não foi feita. Então valeu a pena
tentar
4
@ zfus eu vejo. Pode querer ficar com outro revdepois.
tom
17
revideal duplo grande!
Ford Guo
6
Impressionantes, simples, perfeito, obrigado pela explicação também - não basta as pessoas explicando cada passo em longas cadeias de comandos canalizada
Pete
128
Use uma expansão de parâmetro. Isso é muito mais eficiente do que qualquer tipo de comando externo, cut(ou grep) incluído.
data=foo,bar,baz,qux
last=${data##*,}
Consulte o BashFAQ # 100 para obter uma introdução à manipulação nativa de strings no bash.
@ ErwinWessels: Porque o bash é realmente lento. Use o bash para executar pipelines, não para processar dados em massa. Quero dizer, isso é ótimo se você já tem uma linha de texto em uma variável de shell ou se deseja while IFS= read -ra array_var; do :;done <(cmd)processar algumas linhas. Mas para um arquivo grande, rev | cut | rev é provavelmente mais rápido! (E, claro awk será mais rápido do que isso.)
Peter Cordes
2
@ PeterCordes, o awk será mais rápido para um arquivo grande, com certeza, mas é preciso um pouco de entrada para superar os custos de inicialização com fator constante. (Também existem shells - como o ksh93 - com desempenho mais próximo do awk, onde a sintaxe fornecida nesta resposta permanece válida; o bash é excepcionalmente lento, mas não chega nem perto da única opção disponível).
Charles Duffy
1
Obrigado @PeterCordes; como sempre, acho que cada ferramenta tem seus casos de uso.
Erwin Wessels
1
Essa é de longe a maneira mais rápida e concisa de aparar uma única variável dentro de um bashscript (supondo que você já esteja usando um bashscript). Não há necessidade de chamar nada externo.
Ken afiada
1
@ Balmipour, ... no entanto, revé específico para qualquer sistema operacional que você esteja usando que o fornece - não é padronizado em todos os sistemas UNIX. Veja a lista de capítulos da seção POSIX sobre comandos e utilitários - não está lá. E não${var##prefix_pattern} é , de fato, específico do bash; está no padrão POSIX sh , consulte o final da seção 2.6.2 (vinculada); portanto , ao contrário , está sempre disponível em qualquer shell compatível. rev
Charles Duffy
89
Não é possível usar apenas cut. Aqui está uma maneira de usar grep:
Para fazer o oposto, e encontrar tudo, exceto o último campo fazer:grep -o '^.*,'
Ariel
2
Isso foi especialmente útil, porque revadicione um problema de caracteres unicode multibyte no meu caso.
Brice
3
Eu estava tentando fazer isso no MinGW, mas minha versão grep não suporta -o, então usei o sed 's/^.*,//'que substitui todos os caracteres até e incluindo a última vírgula por uma string vazia.
TamaMcGlinn
46
Sem awk? ... Mas é tão simples com awk:
echo 'maps.google.com'| awk -F.'{print $NF}'
AWK é uma ferramenta muito mais poderosa para ter no seu bolso. -F se para o separador de campos NF for o número de campos (também representa o índice dos últimos)
Isso é universal e funciona exatamente como esperado todas as vezes. Nesse cenário, usar cutpara alcançar a saída final do OP é como usar uma colher para "cortar" o bife (trocadilho intencional :)). awké a faca de bife.
Hickory420
3
Evite o uso desnecessário, echopois isso pode atrasar o script para arquivos longos usando awk -F. '{print $NF}' <<< 'maps.google.com'.
Anil_M 17/10/19
14
Existem várias maneiras. Você também pode usar isso.
Usando esta solução, o número de campos pode realmente ser desconhecido e variar de tempos em tempos. No entanto, como o comprimento da linha não deve exceder os caracteres ou campos LINE_MAX, incluindo o caractere de nova linha, um número arbitrário de campos nunca poderá fazer parte como uma condição real desta solução.
Sim, uma solução muito boba, mas a única que atende aos critérios que eu acho.
Isso não usa sedou awktambém não usa cut, então não tenho certeza se ele se qualifica como resposta à pergunta conforme está redigido.
Isso não funciona bem se o processamento de seqüências de entrada que podem conter barras. Uma solução alternativa para essa situação seria substituir a barra por outro caractere que você sabe que não faz parte de uma sequência de entrada válida. Por exemplo, o |caractere pipe ( ) também não é permitido nos nomes de arquivos, portanto, isso funcionaria:
Você precisa de aspas duplas ao redor dos argumentos echopara que isso funcione de maneira confiável e robusta. Veja stackoverflow.com/questions/10067266/…
tripleee
0
Se você tiver um arquivo denominado filelist.txt, é um caminho de lista como o seguinte: c: /dir1/dir2/file1.h c: /dir1/dir2/dir3/file2.h
então você pode fazer isso: rev filelist.txt | corte -d "/" -f1 | rev
Adicionando uma abordagem a essa pergunta antiga apenas por diversão:
$ cat input.file # file containing input that needs to be processed
a;b;c;d;e
1;2;3;4;5
no delimiter here
124;adsf;15454
foo;bar;is;null;info
$ cat tmp.sh # showing off the script to do the job#!/bin/bash
delim=';'while read -r line;dowhile[["$line"=~"$delim"]];do
line=$(cut -d"$delim"-f 2-<<<"$line")done
echo "$line"done< input.file
$ ./tmp.sh # output of above script/processed input file
e
5
no delimiter here
15454
info
Além do bash, apenas o corte é usado. Bem, e eco, eu acho.
Meh, por que não apenas remover o corte completamente e usar apenas o bash ... x] while read -r line; do echo ${line/*;}; done <input.fileproduz o mesmo resultado.
Kaffe Myers
-1
Percebi que se apenas garantirmos que existe um delimitador à direita, ele funciona. Portanto, no meu caso, tenho delimitadores de vírgula e espaço em branco. Eu adiciono um espaço no final;
cut
comando :)? porque não outros comandos do Linux?sed
ouawk
:perl -pe 's/^.+\s+([^\s]+)$/$1/'
.cut
suporta algo que não suporta. Mas achei útil, pois força o leitor a considerar um código mais fácil de seguir. Eu queria um rápido, muito simples de usarcut
, sem necessidade de utilizar várias sintaxes paraawk
,grep
,sed
, etc. Arev
coisa fez o truque; muito elegante e algo que eu nunca considerei (mesmo que desajeitado para outras situações). Também gostei de ler as outras abordagens das outras respostas.find | cut -d. -f<last>
é a inclinação naturalRespostas:
Você pode tentar algo como isto:
Explicação
rev
reverte "maps.google.com" para sermoc.elgoog.spam
cut
usa ponto (ou seja, '.') como delimitador e escolhe o primeiro campo, que émoc
com
fonte
cut
mas está semsed
ouawk
.Então, o que OP pensa?rev
depois.rev
ideal duplo grande!Use uma expansão de parâmetro. Isso é muito mais eficiente do que qualquer tipo de comando externo,
cut
(ougrep
) incluído.Consulte o BashFAQ # 100 para obter uma introdução à manipulação nativa de strings no bash.
fonte
while IFS= read -ra array_var; do :;done <(cmd)
processar algumas linhas. Mas para um arquivo grande, rev | cut | rev é provavelmente mais rápido! (E, claro awk será mais rápido do que isso.)bash
script (supondo que você já esteja usando umbash
script). Não há necessidade de chamar nada externo.rev
é específico para qualquer sistema operacional que você esteja usando que o fornece - não é padronizado em todos os sistemas UNIX. Veja a lista de capítulos da seção POSIX sobre comandos e utilitários - não está lá. E não${var##prefix_pattern}
é , de fato, específico do bash; está no padrão POSIX sh , consulte o final da seção 2.6.2 (vinculada); portanto , ao contrário , está sempre disponível em qualquer shell compatível.rev
Não é possível usar apenas
cut
. Aqui está uma maneira de usargrep
:Substitua a vírgula por outros delimitadores.
fonte
grep -o '^.*,'
rev
adicione um problema de caracteres unicode multibyte no meu caso.sed 's/^.*,//'
que substitui todos os caracteres até e incluindo a última vírgula por uma string vazia.Sem awk? ... Mas é tão simples com awk:
AWK é uma ferramenta muito mais poderosa para ter no seu bolso. -F se para o separador de campos NF for o número de campos (também representa o índice dos últimos)
fonte
cut
para alcançar a saída final do OP é como usar uma colher para "cortar" o bife (trocadilho intencional :)).awk
é a faca de bife.echo
pois isso pode atrasar o script para arquivos longos usandoawk -F. '{print $NF}' <<< 'maps.google.com'
.Existem várias maneiras. Você também pode usar isso.
Obviamente, a entrada de espaço em branco para o comando tr deve ser substituída pelo delimitador necessário.
fonte
Esta é a única solução possível para usar nada além de cortar:
Usando esta solução, o número de campos pode realmente ser desconhecido e variar de tempos em tempos. No entanto, como o comprimento da linha não deve exceder os caracteres ou campos LINE_MAX, incluindo o caractere de nova linha, um número arbitrário de campos nunca poderá fazer parte como uma condição real desta solução.
Sim, uma solução muito boba, mas a única que atende aos critérios que eu acho.
fonte
cut -f2-
em um loop até que a saída não seja mais alterada.Se sua string de entrada não contém barras, você pode usar
basename
e um subshell:Isso não usa
sed
ouawk
também não usacut
, então não tenho certeza se ele se qualifica como resposta à pergunta conforme está redigido.Isso não funciona bem se o processamento de seqüências de entrada que podem conter barras. Uma solução alternativa para essa situação seria substituir a barra por outro caractere que você sabe que não faz parte de uma sequência de entrada válida. Por exemplo, o
|
caractere pipe ( ) também não é permitido nos nomes de arquivos, portanto, isso funcionaria:fonte
o seguinte implementa a sugestão de um amigo
fonte
echo
para que isso funcione de maneira confiável e robusta. Veja stackoverflow.com/questions/10067266/…Se você tiver um arquivo denominado filelist.txt, é um caminho de lista como o seguinte: c: /dir1/dir2/file1.h c: /dir1/dir2/dir3/file2.h
então você pode fazer isso: rev filelist.txt | corte -d "/" -f1 | rev
fonte
Adicionando uma abordagem a essa pergunta antiga apenas por diversão:
Além do bash, apenas o corte é usado. Bem, e eco, eu acho.
fonte
while read -r line; do echo ${line/*;}; done <input.file
produz o mesmo resultado.Percebi que se apenas garantirmos que existe um delimitador à direita, ele funciona. Portanto, no meu caso, tenho delimitadores de vírgula e espaço em branco. Eu adiciono um espaço no final;
fonte
ans="a, b, c"
produzb
, que não atende aos requisitos de "o número de campos é desconhecido ou muda a cada linha" .