Obrigado a todos. Acabei usando 'cut -c1-2', honestamente, eu nem sabia que 'cut' estava lá. Eu gostaria de dizer que tenho bastante experiência na linha de comando - mas aparentemente tenho muito a aprender.
Greg Greg
1
@ Greg, esteja ciente de que o corte é executado como um processo separado - será mais lento que a solução interna do bash que publiquei ao lado na minha resposta. Isso não fará nenhuma diferença, a menos que você esteja processando grandes conjuntos de dados, mas tenha em mente isso.
paxdiablo
Editar Na verdade, acho que essa linha de código provavelmente será executada cerca de 50.000 vezes por relatório. Então, eu posso apenas usar o método Bash interno - que, como você disse, economizará alguns recursos muito necessários.
Provavelmente, o método mais eficiente, se você estiver usando o bashshell (e parece estar, com base nos seus comentários), é usar a variante de sub-string da expansão de parâmetros:
pax> long="USCAGol.blah.blah.blah"
pax> short="${long:0:2}"; echo "${short}"
US
Isso definirá shortos dois primeiros caracteres de long. Se longfor menor que dois caracteres, shortserá idêntico a ele.
Esse método in-shell geralmente é melhor se você o fizer muito (como 50.000 vezes por relatório, como você mencionou), já que não há sobrecarga na criação do processo. Todas as soluções que usam programas externos sofrerão com essa sobrecarga.
Se você também deseja garantir um comprimento mínimo , pode prendê-lo antes da mão com algo como:
pax> long="A"
pax> tmpstr="${long}.."
pax> short="${tmpstr:0:2}"; echo "${short}"
A.
Isso garantiria que algo com menos de dois caracteres fosse preenchido à direita com pontos (ou qualquer outra coisa, apenas alterando o caractere usado ao criar tmpstr). Não está claro se você precisa disso, mas pensei em colocá-lo por completo.
Dito isto, existem várias maneiras de fazer isso com programas externos (como se você não tiver bashdisponível), algumas das quais são:
short=$(echo "${long}"| cut -c1-2)
short=$(echo "${long}"| head -c2)
short=$(echo "${long}"| awk '{print substr ($0, 0, 2)}'
short=$(echo "${long}"| sed 's/^\(..\).*/\1/')
Os dois primeiros ( cute head) são idênticos para uma string de linha única - eles basicamente apenas devolvem os dois primeiros caracteres. Eles diferem no que cutfornecerá os dois primeiros caracteres de cada linha e heados dois primeiros caracteres de toda a entrada
O terceiro usa a awkfunção sub-string para extrair os dois primeiros caracteres e o quarto usa sedgrupos de captura (usando ()e \1) para capturar os dois primeiros caracteres e substituir a linha inteira por eles. Ambos são semelhantes a cut- eles entregam os dois primeiros caracteres de cada linha na entrada.
Nada disso importa se você tiver certeza de que sua entrada é uma única linha, todas elas têm um efeito idêntico.
Eu preferiria usar printf '%s'em vez de echono caso de existirem caracteres estranhos na string: stackoverflow.com/a/40423558/895245 Para o POSIX obcecado: head -cnão é POSIX, cut -ce awk substrsão, sed \1não tenho certeza.
Ciro Santilli #
1
@CiroSantilli 中心 改造 中心 996ICU 事件 print usando printf, você nem precisa de um programa adicional. Veja minha resposta .
bschlueter
60
maneira mais fácil é
${string:position:length}
Onde isso extrai a $lengthsubstring de $stringem $position.
Este é um bash embutido; portanto, awk ou sed não é necessário.
Essa é a maneira mais curta, fácil e fácil de obter a substring.
ani627
34
Você chegou várias respostas boas e eu iria com o Bash builtin mim mesmo, mas já que você perguntou sobre sede awke ( quase ) ninguém mais oferecido soluções com base neles, eu oferecer-lhe estes:
echo "USCAGoleta9311734.5021-120.1287855805"| sed 's/\(^..\).*/\1/'
O awkprimeiro deve ser bastante óbvio, mas aqui está uma explicação sed:
substituto "s /"
o grupo "()" de dois dos caracteres ".." começando no início da linha "^" e seguido por qualquer caractere "." repetido zero ou mais vezes "*" (as barras invertidas são necessárias para escapar de alguns dos caracteres especiais)
por "/" o conteúdo do primeiro (e somente neste caso) grupo (aqui a barra invertida é uma fuga especial referente a uma subexpressão correspondente)
Se você deseja usar scripts de shell e não confiar em extensões não-posix (como os chamados bashismos), você pode usar técnicas que não requerem bifurcação de ferramentas externas, como grep, sed, cut, awk etc., que então torne seu script menos eficiente. Talvez a eficiência e a portabilidade do posix não sejam importantes no seu caso de uso. Mas, caso seja (ou apenas um bom hábito), você pode usar o seguinte método de opção de expansão de parâmetro para extrair os dois primeiros caracteres de uma variável de shell:
$ sh -c 'var=abcde; echo "${var%${var#??}}"'
ab
Isso usa a expansão de parâmetro "menor prefixo" para remover os dois primeiros caracteres (esta é a ${var#??}parte) e, em seguida, a expansão de parâmetro "menor sufixo" (a ${var%parte) para remover a cadeia de caracteres com exceção de dois caracteres, exceto o primeiro valor.
Este método foi descrito anteriormente nesta resposta à pergunta "Shell = Verifique se a variável começa com #". Essa resposta também descreve alguns métodos de expansão de parâmetros semelhantes que podem ser usados em um contexto ligeiramente diferente daquele que se aplica à pergunta original aqui.
Melhor resposta, deve estar no topo. sem garfos, sem basismos. funciona mesmo com pequenas conchas, como traço.
exore
1
Se o seu sistema estiver usando um shell diferente (não bash), mas o seu sistema tiver bash, você ainda poderá usar a manipulação de string inerente bashinvocando bashcom uma variável:
strEcho='echo ${str:0:2}'# '${str:2}' if you want to skip the first two characters and keep the rest
bash -c "str=\"$strFull\";$strEcho;"
Isso usa o mesmo método da resposta principal , invocando apenas bashse você ainda não o estiver usando.
palswim
Infelizmente, isso vem com toda a sobrecarga de invocar outro processo, mas às vezes essa sobrecarga não importa tanto quanto simplicidade e familiaridade.
palswim
1
Só por diversão, acrescentarei alguns que, apesar de complicados e inúteis, não foram mencionados:
como é provável que ele / ela esteja chamando isso a partir do shell, uma forma melhor seriaperl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'
Respostas:
Provavelmente, o método mais eficiente, se você estiver usando o
bash
shell (e parece estar, com base nos seus comentários), é usar a variante de sub-string da expansão de parâmetros:Isso definirá
short
os dois primeiros caracteres delong
. Selong
for menor que dois caracteres,short
será idêntico a ele.Esse método in-shell geralmente é melhor se você o fizer muito (como 50.000 vezes por relatório, como você mencionou), já que não há sobrecarga na criação do processo. Todas as soluções que usam programas externos sofrerão com essa sobrecarga.
Se você também deseja garantir um comprimento mínimo , pode prendê-lo antes da mão com algo como:
Isso garantiria que algo com menos de dois caracteres fosse preenchido à direita com pontos (ou qualquer outra coisa, apenas alterando o caractere usado ao criar
tmpstr
). Não está claro se você precisa disso, mas pensei em colocá-lo por completo.Dito isto, existem várias maneiras de fazer isso com programas externos (como se você não tiver
bash
disponível), algumas das quais são:Os dois primeiros (
cut
ehead
) são idênticos para uma string de linha única - eles basicamente apenas devolvem os dois primeiros caracteres. Eles diferem no quecut
fornecerá os dois primeiros caracteres de cada linha ehead
os dois primeiros caracteres de toda a entradaO terceiro usa a
awk
função sub-string para extrair os dois primeiros caracteres e o quarto usased
grupos de captura (usando()
e\1
) para capturar os dois primeiros caracteres e substituir a linha inteira por eles. Ambos são semelhantes acut
- eles entregam os dois primeiros caracteres de cada linha na entrada.Nada disso importa se você tiver certeza de que sua entrada é uma única linha, todas elas têm um efeito idêntico.
fonte
printf '%s'
em vez deecho
no caso de existirem caracteres estranhos na string: stackoverflow.com/a/40423558/895245 Para o POSIX obcecado:head -c
não é POSIX,cut -c
eawk substr
são,sed \1
não tenho certeza.maneira mais fácil é
Onde isso extrai a
$length
substring de$string
em$position
.Este é um bash embutido; portanto, awk ou sed não é necessário.
fonte
Você chegou várias respostas boas e eu iria com o Bash builtin mim mesmo, mas já que você perguntou sobre
sed
eawk
e ( quase ) ninguém mais oferecido soluções com base neles, eu oferecer-lhe estes:e
O
awk
primeiro deve ser bastante óbvio, mas aqui está uma explicaçãosed
:fonte
substr($0,1,2)
.Se você estiver dentro
bash
, pode dizer:Isso pode ser exatamente o que você precisa ...
fonte
Apenas grep:
fonte
-P
opção para torná-la mais curta. Todos os regexs entenderão esse padrão.Você pode usar
printf
:fonte
colrm - remove colunas de um arquivo
Para deixar os dois primeiros caracteres, remova as colunas começando em 3
fonte
Muito tarde, de fato, mas aqui está
Ou
Ou
fonte
Se você deseja usar scripts de shell e não confiar em extensões não-posix (como os chamados bashismos), você pode usar técnicas que não requerem bifurcação de ferramentas externas, como grep, sed, cut, awk etc., que então torne seu script menos eficiente. Talvez a eficiência e a portabilidade do posix não sejam importantes no seu caso de uso. Mas, caso seja (ou apenas um bom hábito), você pode usar o seguinte método de opção de expansão de parâmetro para extrair os dois primeiros caracteres de uma variável de shell:
Isso usa a expansão de parâmetro "menor prefixo" para remover os dois primeiros caracteres (esta é a
${var#??}
parte) e, em seguida, a expansão de parâmetro "menor sufixo" (a${var%
parte) para remover a cadeia de caracteres com exceção de dois caracteres, exceto o primeiro valor.Este método foi descrito anteriormente nesta resposta à pergunta "Shell = Verifique se a variável começa com #". Essa resposta também descreve alguns métodos de expansão de parâmetros semelhantes que podem ser usados em um contexto ligeiramente diferente daquele que se aplica à pergunta original aqui.
fonte
Se o seu sistema estiver usando um shell diferente (não
bash
), mas o seu sistema tiverbash
, você ainda poderá usar a manipulação de string inerentebash
invocandobash
com uma variável:fonte
bash
se você ainda não o estiver usando.Só por diversão, acrescentarei alguns que, apesar de complicados e inúteis, não foram mencionados:
fonte
fonte
se mystring = USCAGoleta9311734.5021-120.1287855805
imprimiria EUA
onde 0 é a posição inicial e 2 é como meny chars para ler
fonte
awk
. Desculpe, eu não sabia dizer a princípio.É isso que você procura?
ref: substr
fonte
perl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'