Tengo este pequeño script en sh
(Mac OSX 10.6) para mirar a través de una variedad de archivos. Google ha dejado de ser útil en este punto:
files="*.jpg"
for f in $files
do
echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
name=$?
echo $name
done
Hasta ahora (obviamente, para ustedes gurús de shell) $name
simplemente tiene 0, 1 o 2, dependiendo de si se grep
encontró que el nombre del archivo coincide con el asunto proporcionado. Lo que me gustaría es capturar lo que hay dentro de los padres ([a-z]+)
y almacenarlo en una variable .
Me gustaría usar grep
solo, si es posible . Si no es así, no use Python o Perl, etc. sed
o algo así: soy nuevo en shell y me gustaría atacar esto desde el ángulo purista * nix.
Además, como bonificaciones súper geniales , tengo curiosidad por saber cómo puedo concatenar la cuerda en la concha. ¿El grupo que capturé era la cadena "somename" almacenada en $ name, y quería agregar la cadena ".jpg" al final, ¿podría cat $name '.jpg'
?
Por favor explique qué está pasando, si tiene tiempo.
grep
, entoncessed
sería genial, si es posible resolver usandosed
.Respuestas:
Si está usando Bash, ni siquiera tiene que usar
grep
:Es mejor poner la expresión regular en una variable. Algunos patrones no funcionarán si se incluyen literalmente.
Esto utiliza
=~
cuál es el operador de coincidencia de expresiones regulares de Bash. Los resultados del partido se guardan en una matriz llamada$BASH_REMATCH
. El primer grupo de captura se almacena en el índice 1, el segundo (si lo hay) en el índice 2, etc. El índice cero es la coincidencia completa.Debe tener en cuenta que sin las anclas, esta expresión regular (y la que usa
grep
) coincidirá con cualquiera de los siguientes ejemplos y más, que pueden no ser lo que está buscando:Para eliminar los ejemplos segundo y cuarto, haga su expresión regular de esta manera:
que dice que la cadena debe comenzar con uno o más dígitos. El quilate representa el comienzo de la cadena. Si agrega un signo de dólar al final de la expresión regular, así:
entonces el tercer ejemplo también será eliminado ya que el punto no está entre los caracteres en la expresión regular y el signo de dólar representa el final de la cadena. Tenga en cuenta que el cuarto ejemplo también falla en esta coincidencia.
Si tiene GNU
grep
(alrededor de 2.5 o posterior, creo, cuando\K
se agregó el operador):El
\K
operador (retrospectiva de longitud variable) hace que el patrón anterior coincida, pero no incluye la coincidencia en el resultado. El equivalente de longitud fija es(?<=)
: el patrón se incluiría antes del paréntesis de cierre. Debe usar\K
si los cuantificadores pueden coincidir con cadenas de diferentes longitudes (p+
. Ej .*
,{2,4}
).El
(?=)
operador coincide con patrones de longitud fija o variable y se llama "mirar hacia adelante". Tampoco incluye la cadena coincidente en el resultado.Para que la coincidencia no distinga entre mayúsculas y minúsculas,
(?i)
se utiliza el operador. Afecta los patrones que lo siguen, por lo que su posición es significativa.Es posible que sea necesario ajustar la expresión regular dependiendo de si hay otros caracteres en el nombre del archivo. Notarás que en este caso, muestro un ejemplo de concatenación de una cadena al mismo tiempo que se captura la subcadena.
fuente
/K
operador de rocas.grep
. También fue aceptado por el OP y votó bastante. Gracias por el voto negativo.Esto no es realmente posible con puro
grep
, al menos en general.Pero si su patrón es adecuado, puede usarlo
grep
varias veces dentro de una tubería para reducir primero su línea a un formato conocido y luego extraer solo el bit que desee. (Aunque las herramientas les gustancut
ysed
son mucho mejores en esto).Supongamos, por el argumento, que su patrón es un poco más simple:
[0-9]+_([a-z]+)_
podría extraer esto de esta manera:El primero
grep
eliminaría cualquier línea que no coincidiera con su patrón general, el segundogrep
(que ha--only-matching
especificado) mostrará la parte alfa del nombre. Esto solo funciona porque el patrón es adecuado: la "porción alfa" es lo suficientemente específica como para extraer lo que desea.(Aparte: Personalmente, usaría
grep
+cut
para lograr lo que busca:echo $name | grep {pattern} | cut -d _ -f 2
estocut
permite analizar la línea en campos al dividir en el delimitador_
, y devuelve solo el campo 2 (los números de campo comienzan en 1)).La filosofía de Unix es tener herramientas que hacen una cosa, y lo hacen bien, y combinarlas para lograr tareas no triviales, por lo que diría que
grep
+sed
etc es una forma más Unixy de hacer las cosas :-)fuente
for f in $files; do name=
echo $ f | grep -oEi '[0-9] + _ ([az] +) _ [0-9a-z] *' | corte -d _ -f 2;
¡Ajá!Me doy cuenta de que ya se aceptó una respuesta para esto, pero desde un "ángulo estrictamente * nix purista" parece que la herramienta adecuada para el trabajo es
pcregrep
, lo que parece no haber sido mencionado todavía. Intenta cambiar las líneas:a lo siguiente:
para obtener solo los contenidos del grupo de captura 1.
La
pcregrep
herramienta utiliza la misma sintaxis que ya usógrep
, pero implementa la funcionalidad que necesita.El parámetro
-o
funciona igual que lagrep
versión si es simple , pero también acepta un parámetro numéricopcregrep
, que indica qué grupo de captura desea mostrar.Con esta solución, se requiere un mínimo de cambio en el script. Simplemente reemplace una utilidad modular con otra y modifique los parámetros.
Nota interesante: puede usar múltiples argumentos -o para devolver múltiples grupos de captura en el orden en que aparecen en la línea.
fuente
pcregrep
no está disponible por defecto,Mac OS X
que es lo que usa el OPpcregrep
parece no entender el dígito después de-o
: "Letra de opción desconocida '1' en" -o1 ". Tampoco se menciona esa funcionalidad cuando se mirapcregrep --help
7.8 2008-09-05
.echo 'r123456 foo 2016-03-17' | pcregrep -o1 'r([0-9]+)' 123456
pcregrep
8.41 (instalado conapt-get install pcregrep
encendidoUbuntu 16.03
) no reconoce el-Ei
interruptor. Sin embargo, funciona perfectamente sin él. En macOS, conpcregrep
instalado a través dehomebrew
(también 8.41) como @anishpatel menciona anteriormente, al menos en High Sierra-E
tampoco se reconoce el interruptor.No es posible solo con grep, creo
para sed:
Sin embargo, probaré la bonificación:
fuente
sed
solución no funciona. Simplemente imprime todo en mi directorio.Esta es una solución que usa gawk. Es algo que creo que necesito usar a menudo, así que creé una función para ello.
para usar solo hacer
fuente
\s
. ¿Sabes cómo solucionarlo?Una sugerencia para usted: puede usar la expansión de parámetros para eliminar la parte del nombre del último guión bajo y, de manera similar, al principio:
Entonces
name
tendrá el valorabc
.Consulte los documentos para desarrolladores de Apple , busque 'Expansión de parámetros'.
fuente
si tienes bash, puedes usar globbing extendido
o
fuente