2009-09-10 15 views
76

Soy nuevo en sed y awk, por lo que no estoy seguro de cuál es la forma más eficiente de hacerlo.Extracción de los dos primeros caracteres de una cadena (Creación de secuencias de comandos de shell)

Estoy buscando extraer las dos primeras letras de una cadena. Podría hacerlo si iban a ser el mismo cada vez, pero me parece que no puede encontrar la manera de decir simplemente,

tomar la N posiciones de esta cadena a partir de esta cadena más grande x.

IE.

 
USCAGoleta9311734.5021-120.1287855805 = US 
+3

Gracias a todos. Terminé usando 'cut -c1-2', sinceramente ni siquiera sabía que 'cut' estaba allí. Me gustaría decir que tengo mucha experiencia en la línea de comandos, pero aparentemente tengo mucho que aprender. – Greg

+1

@Greg, solo tenga en cuenta que el corte se ejecuta como un proceso separado; será más lento que la solución de bash interna que publiqué junto a él en mi respuesta. Eso no hará ninguna diferencia a menos que esté procesando grandes conjuntos de datos, pero debe tenerlo en cuenta. – paxdiablo

+0

[Editar] En realidad, creo que esta línea de código probablemente se ejecutará aproximadamente 50,000 veces por informe. Así que podría ir con el método interno de Bash, que como dijiste ahorrará algunos recursos muy necesarios. – Greg

Respuesta

29

forma más fácil es

${string:position:length} 

Cuando esto extrae $length parcial de caracteres de $string en $position.

Esto es un bash incorporado por lo que no se requiere awk o sed.

+0

Esta es la manera corta, dulce y fácil de obtener la subcadena. – user1336087

108

Probablemente el método más eficiente, si usted está utilizando la cáscara bash (y que parecen ser, en función de sus comentarios), es el uso de la variante subcadena de la expansión de parámetros:

pax> long="USCAGol.blah.blah.blah" 
pax> short="${long:0:2}" ; echo "${short}" 
US 

Esto configurará short como los primeros dos caracteres de long. Si long es más corto que dos caracteres, short será idéntico.

Este método en el caparazón generalmente es mejor si vas a estar haciéndolo mucho (como 50,000 veces por informe como mencionas) ya que no hay una sobrecarga de creación de proceso. Todas las soluciones que usan programas externos sufrirán por esa sobrecarga.

Si también quería asegurar una longitud mínima , usted podría almohadilla a cabo antes de la mano con algo como:

pax> long="A" 
pax> tmpstr="${long}.." 
pax> short="${tmpstr:0:2}" ; echo "${short}" 
A. 

Esto aseguraría que cualquier cosa menos de dos caracteres de longitud fue rellenada por la derecha con puntos (u otra cosa, simplemente cambiando el carácter utilizado al crear tmpstr). No está claro que necesites esto, pero pensé que lo pondría para completarlo.


Una vez dicho esto, hay un número de maneras de hacer esto con programas externos (por ejemplo, si usted no tiene a su disposición bash), algunos de los cuales son:

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/') 

Los primeros dos (cut y head) son idénticos para una cadena de una sola línea; básicamente, ambos simplemente le devuelven los dos primeros caracteres. Se diferencian en que cut le dará los dos primeros caracteres de cada línea y head le dará los dos primeros caracteres de la entrada completa

El tercero utiliza la función awk sub-cadena para extraer los dos primeros caracteres y la cuarto usa sed grupos de captura (usando () y \1) para capturar los primeros dos caracteres y reemplazar la línea completa con ellos.Ambos son similares a cut - entregan los primeros dos caracteres de cada línea en la entrada.

Nada de eso importa si está seguro de que su entrada es una sola línea, todas tienen un efecto idéntico.

0

¿Es esto lo que buscas?

my $string = 'USCAGoleta9311734.5021-120.1287855805'; 

my $first_two_chars = substr $string, 0, 2; 

ref: substr

+1

dado que es probable que llame a esto desde el shell, una forma mejor sería 'perl -e 'print substr $ ARGV [0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'' –

0

si mystring = USCAGoleta9311734.5021-120.1287855805

print substr(mystring,0,2) 

imprimiría estadounidense

donde 0 es la posición de inicio y 2 es la forma en caracteres Meny a leer

+0

Diga .. ¿No es ese GW-BASIC? Oh, espera, eso es 'awk'. Lo siento, no pude decirlo al principio. –

0
perl -ple 's/^(..).*/$1/' 
+0

Olvidó hacer eco de la cadena en eso. –

+0

No, yo no ... dice STDIN – dsm

29

usted ha conseguido varias buenas respuestas y me gustaría ir con la orden interna Bash mí mismo, pero ya que preguntas acerca sed y awk y ( casi) nadie más soluciones que se ofrecen en base a ellas, les ofrezco estos:

echo "USCAGoleta9311734.5021-120.1287855805" | awk '{print substr($0,0,2)}' 

y

echo "USCAGoleta9311734.5021-120.1287855805" | sed 's/\(^..\).*/\1/' 

el awk uno debe ser bastante obvio, pero aquí es una explicación de la sed uno:

  • sustituto "s /"
  • el grupo "()" de dos de los caracteres ".." comenzando al principio de la línea "^" y seguidos de cualquier carácter "."repite cero o más veces" * "(las barras diagonales inversas son necesarias para escapar de algunos de los caracteres especiales)
  • por"/"el contenido del primer grupo (y solo, en este caso) (aquí la barra invertida es especial escapar en referencia a un juego sub-expresión)
  • hecho "/"
3

colrm - eliminar columnas de un archivo

para dejar dos primeros caracteres, basta con retirar columnas partiendo de 3

cat file | colrm 3 
3

Si estás en bash, se puede decir:

bash-3.2$ var=abcd 
bash-3.2$ echo ${var:0:2} 
ab 

esto puede ser justo lo que necesita ...

+1

Lo siento, no vi que Pax ya haya publicado esto. –

+0

¡la respuesta más fácil y simple! funcionó como un amuleto – aloha

3

de hecho bastante tarde pero aquí es

sed 's/.//3g' 

O

awk NF=1 FPAT=.. 

O

perl -pe '$_=unpack a2' 
3

Sólo grep:

echo 'abcdef' | grep -Po "^.."  # ab 
1

Si su sistema está utilizando un shell diferente (no bash), pero el sistema dispone de bash, a continuación, puede seguir utilizando la manipulación de cadenas inherente de bash invocando bash con una variable:

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;" 
+0

Esto usa el mismo método que [la respuesta principal] (http://stackoverflow.com/a/1405641/393280), solo invocando 'bash' si aún no lo está usando. – palswim

+0

Lamentablemente, esto viene con todos los gastos generales de invocar a otro proceso, pero a veces esa sobrecarga no importa tanto como la simplicidad y la familiaridad. – palswim

Cuestiones relacionadas