Gracias a todos. Terminé usando 'cut -c1-2', honestamente, ni siquiera sabía que 'cut' estaba allí. Me gustaría decir que tengo bastante experiencia en la línea de comandos, pero aparentemente tengo mucho que aprender.
Greg
1
@ Greg, solo ten en cuenta que el corte se ejecuta como un proceso separado: será más lento que la solución de bash interno 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
Editar En realidad, creo que esta línea de código probablemente se ejecutará unas 50,000 veces por informe. Por lo tanto, podría seguir con el método interno de Bash, que como dijiste ahorrará algunos recursos muy necesarios.
Probablemente el método más eficiente, si está utilizando el bashshell (y parece que lo es, según sus comentarios), es usar la variante de subcadena de expansión de parámetros:
pax> long="USCAGol.blah.blah.blah"
pax> short="${long:0:2}"; echo "${short}"
US
Esto se establecerá shortpara ser los dos primeros caracteres de long. Si longes más corto que dos caracteres, shortserá idéntico a él.
Este método de shell generalmente es mejor si lo vas a hacer mucho (como 50,000 veces por informe como mencionas) ya que no hay sobrecarga de creación de procesos. Todas las soluciones que utilizan programas externos sufrirán esa sobrecarga.
Si también quisieras asegurar una longitud mínima , puedes rellenarlo de antemano con algo como:
pax> long="A"
pax> tmpstr="${long}.."
pax> short="${tmpstr:0:2}"; echo "${short}"
A.
Esto garantizaría que algo menos de dos caracteres de longitud se rellenara a la derecha con puntos (o algo más, simplemente cambiando el carácter utilizado al crear tmpstr). No está claro que necesites esto, pero pensé que lo pondría completo.
Dicho esto, hay varias maneras de hacer esto con programas externos (por ejemplo, si no tiene a su bashdisposición), algunas de las 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 ( cuty head) son idénticos para una cadena de una sola línea; básicamente, ambos solo le devuelven los dos primeros caracteres. Se diferencian en que cutle dará los dos primeros caracteres de cada línea yhead le dará los dos primeros caracteres de toda la entrada.
El tercero usa la awkfunción de subcadena para extraer los dos primeros caracteres y el cuarto usa los sedgrupos de captura (usando ()y \1) para capturar los dos primeros caracteres y reemplazar toda la línea con ellos. Ambos son similares a cut: entregan los dos primeros 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.
Prefiero usar printf '%s'en lugar de echoen el caso de que haya caracteres extraños en la cadena: stackoverflow.com/a/40423558/895245 Para el POSIX obsesionado: head -cno es POSIX, cut -cy awk substrson, sed \1no estoy seguro.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
@CiroSantilli 新疆 改造 中心 996ICU 六四 事件 usando printf, ni siquiera necesita un programa adicional. Mira mi respuesta .
bschlueter
60
la forma más fácil es
${string:position:length}
Donde esto extrae la $lengthsubcadena de $stringat$position .
Este es un bash incorporado así que no se requiere awk o sed.
Esta es la forma corta, dulce y fácil de obtener la subcadena.
ani627
34
Usted ha conseguido varias respuestas buenas y me gustaría ir con el Bash incorporado a mí mismo, pero ya que preguntas acerca sedy awky ( casi soluciones) que nadie más ofrece en base a ellas, les ofrecen éstas:
echo "USCAGoleta9311734.5021-120.1287855805"| sed 's/\(^..\).*/\1/'
El awkuno debería ser bastante obvio, pero aquí hay una explicación sed:
sustituto "s /"
el grupo "()" de dos de los caracteres ".." que comienza al principio de la línea "^" y seguido de cualquier carácter "." repetido cero o más veces "*" (las barras invertidas son necesarias para escapar de algunos de los caracteres especiales)
por "/" el contenido del primer (y único, en este caso) grupo (aquí la barra invertida es un escape especial que se refiere a una sub-expresión coincidente)
Si desea utilizar secuencias de comandos de shell y no confiar en extensiones que no son posix (como los llamados bashisms), puede utilizar técnicas que no requieren herramientas externas de forking como grep, sed, cut, awk, etc., que luego Haz que tu guión sea menos eficiente. Quizás la eficiencia y la portabilidad posix no sean importantes en su caso de uso. Pero en caso de que lo sea (o simplemente como un buen hábito), puede usar el siguiente método de opción de expansión de parámetros para extraer los dos primeros caracteres de una variable de shell:
$ sh -c 'var=abcde; echo "${var%${var#??}}"'
ab
Utiliza la expansión del parámetro "prefijo más pequeño" para eliminar los dos primeros caracteres (esta es la ${var#??}parte), luego la expansión del parámetro "sufijo más pequeño" (el${var% parte) para eliminar la cadena de todo menos los dos primeros caracteres del original valor.
Este método se describió previamente en esta respuesta a la pregunta "Shell = Verificar si la variable comienza con #". Esa respuesta también describe un par de métodos de expansión de parámetros similares que se pueden usar en un contexto ligeramente diferente al que se aplica a la pregunta original aquí.
La mejor respuesta, debería estar en la cima. sin tenedores, sin bashisms. funciona incluso con conchas pequeñas como el tablero.
exore
1
Si su sistema está usando un shell diferente (no bash), pero su sistema sí bash, aún puede usar la manipulación de cadena inherente bashinvocando bashcon 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;"
Utiliza el mismo método que la respuesta principal , solo invoca bashsi aún no lo está utilizando.
palswim
Desafortunadamente, esto viene con toda la sobrecarga de invocar otro proceso, pero a veces esa sobrecarga no importa tanto como la simplicidad y la familiaridad.
palswim
1
Solo por diversión, agregaré algunos que, aunque son demasiado complicados e inútiles, no se mencionaron:
dado que es probable que él / ella esté llamando esto desde la cáscara, una mejor forma seríaperl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'
Respuestas:
Probablemente el método más eficiente, si está utilizando el
bash
shell (y parece que lo es, según sus comentarios), es usar la variante de subcadena de expansión de parámetros:Esto se establecerá
short
para ser los dos primeros caracteres delong
. Silong
es más corto que dos caracteres,short
será idéntico a él.Este método de shell generalmente es mejor si lo vas a hacer mucho (como 50,000 veces por informe como mencionas) ya que no hay sobrecarga de creación de procesos. Todas las soluciones que utilizan programas externos sufrirán esa sobrecarga.
Si también quisieras asegurar una longitud mínima , puedes rellenarlo de antemano con algo como:
Esto garantizaría que algo menos de dos caracteres de longitud se rellenara a la derecha con puntos (o algo más, simplemente cambiando el carácter utilizado al crear
tmpstr
). No está claro que necesites esto, pero pensé que lo pondría completo.Dicho esto, hay varias maneras de hacer esto con programas externos (por ejemplo, si no tiene a su
bash
disposición), algunas de las cuales son:Los primeros dos (
cut
yhead
) son idénticos para una cadena de una sola línea; básicamente, ambos solo le devuelven los dos primeros caracteres. Se diferencian en quecut
le dará los dos primeros caracteres de cada línea yhead
le dará los dos primeros caracteres de toda la entrada.El tercero usa la
awk
función de subcadena para extraer los dos primeros caracteres y el cuarto usa lossed
grupos de captura (usando()
y\1
) para capturar los dos primeros caracteres y reemplazar toda la línea con ellos. Ambos son similares acut
: entregan los dos primeros 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.
fuente
printf '%s'
en lugar deecho
en el caso de que haya caracteres extraños en la cadena: stackoverflow.com/a/40423558/895245 Para el POSIX obsesionado:head -c
no es POSIX,cut -c
yawk substr
son,sed \1
no estoy seguro.la forma más fácil es
Donde esto extrae la
$length
subcadena de$string
at$position
.Este es un bash incorporado así que no se requiere awk o sed.
fuente
Usted ha conseguido varias respuestas buenas y me gustaría ir con el Bash incorporado a mí mismo, pero ya que preguntas acerca
sed
yawk
y ( casi soluciones) que nadie más ofrece en base a ellas, les ofrecen éstas:y
El
awk
uno debería ser bastante obvio, pero aquí hay una explicaciónsed
:fuente
substr($0,1,2)
.Si estás dentro
bash
, puedes decir:Esto puede ser justo lo que necesitas ...
fuente
Solo grep:
fuente
-P
opción para acortarla. Todas las expresiones regulares entenderán ese patrón.Puedes usar
printf
:fuente
colrm - elimina columnas de un archivo
Para dejar los dos primeros caracteres, simplemente elimine las columnas a partir de 3
fuente
Muy tarde, pero aquí está
O
O
fuente
Si desea utilizar secuencias de comandos de shell y no confiar en extensiones que no son posix (como los llamados bashisms), puede utilizar técnicas que no requieren herramientas externas de forking como grep, sed, cut, awk, etc., que luego Haz que tu guión sea menos eficiente. Quizás la eficiencia y la portabilidad posix no sean importantes en su caso de uso. Pero en caso de que lo sea (o simplemente como un buen hábito), puede usar el siguiente método de opción de expansión de parámetros para extraer los dos primeros caracteres de una variable de shell:
Utiliza la expansión del parámetro "prefijo más pequeño" para eliminar los dos primeros caracteres (esta es la
${var#??}
parte), luego la expansión del parámetro "sufijo más pequeño" (el${var%
parte) para eliminar la cadena de todo menos los dos primeros caracteres del original valor.Este método se describió previamente en esta respuesta a la pregunta "Shell = Verificar si la variable comienza con #". Esa respuesta también describe un par de métodos de expansión de parámetros similares que se pueden usar en un contexto ligeramente diferente al que se aplica a la pregunta original aquí.
fuente
Si su sistema está usando un shell diferente (no
bash
), pero su sistema síbash
, aún puede usar la manipulación de cadena inherentebash
invocandobash
con una variable:fuente
bash
si aún no lo está utilizando.Solo por diversión, agregaré algunos que, aunque son demasiado complicados e inútiles, no se mencionaron:
fuente
fuente
si mystring = USCAGoleta9311734.5021-120.1287855805
nos imprimiría
donde 0 es la posición de inicio y 2 es cómo muchos caracteres para leer
fuente
awk
. Lo siento, no pude saber al principio.¿Es esto lo que buscas?
ref: substr
fuente
perl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'