Estoy intentando extraer una lista de archivos definidos en mi archivo .gitattributes en bash.
El archivo .gitattributes tiene este aspecto
#
# Exclude these files from release archives.
# This will also make them unavailable when using Composer with `--prefer-dist`.
# https://blog.madewithlove.be/post/gitattributes/
#
/.git export-ignore
/.github export-ignore
/bin export-ignore
/wp-content/themes/**/.storybook export-ignore
/wp-content/themes/**/assets export-ignore
/wp-content/themes/**/storybook export-ignore
/wp-content/themes/**/tests export-ignore
/wp-content/themes/**/.editorconfig export-ignore
/wp-content/themes/**/.env.testing export-ignore
/wp-content/themes/**/.eslintignore export-ignore
/wp-content/themes/**/.eslintrc export-ignore
/wp-content/themes/**/.gitignore export-ignore
/wp-content/themes/**/.stylelintrc export-ignore
/wp-content/themes/**/babel.config.js export-ignore
/wp-content/themes/**/composer.json export-ignore
/wp-content/themes/**/composer.lock export-ignore
/wp-content/themes/**/package.json export-ignore
/wp-content/themes/**/package-lock.json export-ignore
/wp-content/themes/**/phpcs.xml.dist export-ignore
/wp-content/themes/**/phpstan.neon export-ignore
/wp-content/themes/**/phpstan.neon.dist export-ignore
/wp-content/themes/**/postcss.config.js export-ignore
/wp-content/themes/**/webpack.config.js export-ignore
/wp-content/themes/**/CODE_OF_CONDUCT.md export-ignore
composer.lock -diff
yarn.lock -diff
package.lock -diff
#
# Auto detect text files and perform LF normalization
# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
#
* text=auto
#
# The above will handle all files NOT found below
#
*.md text
*.php text
*.inc text
Mi script bash está dentro de la carpeta bin/ y mis atributos .gitattributes están en la raíz del proyecto.
sh bin/test.sh path
El script se ve así
#!/bin/bash
# - current_path variable (root)
file_list=()
while read -r line; do
if [[ "$line" =~ (\/wp-content\/themes\/\*\*/) ]]; then
newline=$(echo "$line" | sed 's/ export-ignore//p' | sed 's/\/wp-content\/themes\/\*\*\///p')
file_list+=("$newline")
fi
done <""/.gitattributes
echo "${file_list[@]}"
Pero esto me devolverá varios archivos duplicados (cuatro veces). Cuando ejecuto esto me sale
.storybook
.storybook
.storybook
.storybook assets
assets
assets
assets storybook
storybook
storybook
storybook tests
tests
tests
tests .editorconfig
.editorconfig
.editorconfig
.editorconfig .env.testing
.env.testing
.env.testing
.env.testing .eslintignore
.eslintignore
.eslintignore
.eslintignore .eslintrc
.eslintrc
.eslintrc
.eslintrc .gitignore
.gitignore
.gitignore
.gitignore .stylelintrc
.stylelintrc
.stylelintrc
.stylelintrc babel.config.js
babel.config.js
babel.config.js
babel.config.js composer.json
composer.json
composer.json
composer.json composer.lock
composer.lock
composer.lock
composer.lock package.json
package.json
package.json
package.json package-lock.json
package-lock.json
package-lock.json
package-lock.json phpcs.xml.dist
phpcs.xml.dist
phpcs.xml.dist
phpcs.xml.dist phpstan.neon
phpstan.neon
phpstan.neon
phpstan.neon phpstan.neon.dist
phpstan.neon.dist
phpstan.neon.dist
phpstan.neon.dist postcss.config.js
postcss.config.js
postcss.config.js
postcss.config.js webpack.config.js
webpack.config.js
webpack.config.js
webpack.config.js CODE_OF_CONDUCT.md
CODE_OF_CONDUCT.md
CODE_OF_CONDUCT.md
CODE_OF_CONDUCT.md
Resultado esperado:
.storybook
assets
storybook
tests
.editorconfig
.env.testing
.eslintignore
.eslintrc
.gitignore
.stylelintrc
babel.config.js
composer.json
composer.lock
package.json
package-lock.json
phpcs.xml.dist
phpstan.neon
phpstan.neon.dist
postcss.config.js
webpack.config.js
CODE_OF_CONDUCT.md
¿Qué estoy haciendo mal?
¿Cuál es el resultado esperado?
- anubhava27/03/2021 a las 14:19
1
Igual que el anterior pero con un solo archivo, no varios. Gracias por el apoyo. Agregaré el resultado esperado 👍🏼
-dingo_d27/03/2021 a las 14:35
1
Un consejo: no uses sh para ejecutar un script bash o cualquier otro script. Es como ejecutar sh ./my_python_script.py. En algunos sistemastem sh apunta a otra cosa y no a bash, así que espere algún resultado inesperado. Además, incrustar sed dentro de un bucle de lectura while no es ideal ya que sed tendrá que ejecutarse en cada línea, digamos que tiene 1k líneas para procesar y luego sed también tendrá que ejecutarse 1k veces. Sin mencionar que estás transmitiendo sed tras sed.
- Jetchisel27/03/2021 a las 14:53
1
¡Gracias por el consejo! Arreglará esto. Este script debe ejecutarse en acciones de GH, así veré qué erroresLo sabré cuando lo probaré 👍🏼
-dingo_d27/03/2021 a las 14:59
Como probablemente otros señalarán, existen otras formas (más simples y más eficientes) de hacer lo que el OP busca hacer; El objetivo de esta respuesta es abordar el comportamiento del código sed actual del OP.
Por defecto, sed pasará la entrada a la salida estándar. Considere:
$ line='/wp-content/themes/**/.storybook export-ignore'
$ echo "${line}" | sed 's/ export-ignore//'
/wp-content/themes/**/.storybook
Al agregar la directiva p al comando sed, le estás diciendo a sed que imprima el resultado en la salida estándar. Considere:
$ line='/wp-content/themes/**/.storybook export-ignore'
$ echo "${line}" | sed 's/ export-ignore//p'
/wp-content/themes/**/.storybook
/wp-content/themes/**/.storybook
Como puede ver, obtenemos 2 conjuntos de resultados... un conjunto debido al comportamiento normal de sed... un conjunto debido a la directiva p adicional.
Si desea utilizar la directiva p y eliminar la salida 'duplicada', puede agregar el indicador -n (también conocido como --quiet/--silent) que deshabilita el comportamiento predeterminado de sed de pasar la entrada a la salida estándar. Considere:
$ line='/wp-content/themes/**/.storybook export-ignore'
$ echo "${line}" | sed -n 's/ export-ignore//p'
/wp-content/themes/**/.storybook
Debido a que tiene 2 comandos sed usando la directiva p, mientras no usa el indicador -n, termina con un total de 4 copias de cada entrada coincidente (el primer sed genera 2 líneas de salida; el segundo sed luego duplica la salida nuevamente).
Para eliminar los 'duplicados' hay un par de opciones:
elimine la directiva p de ambos comandos sed o ... agregue el indicador -n a ambos comandos sed1
1
Excelente explicación y eso solucionó mi problema. No entendí por completo el objetivo de p, no uso bash con tanta frecuencia, así que pensé que es un delimitador para sed 😅
-dingo_d27/03/2021 a las 14:47
Esto se puede hacer usando un simple awk:
awk -F/ 'index(while read -r line; do
if [[ "$line" =~ (\/wp-content\/themes\/\*\*/) ]]; then
echo "$line" | sed 's/ export-ignore//' | sed 's/\/wp-content\/themes\/\*\*\///'
fi
done <""/.gitattributes
, "/wp-content/themes/") == 1 {sub(/ .*/, "", $NF); print $NF}' .gitattributes
.storybook
assets
storybook
tests
.editorconfig
.env.testing
.eslintignore
.eslintrc
.gitignore
.stylelintrc
babel.config.js
composer.json
composer.lock
package.json
package-lock.json
phpcs.xml.dist
phpstan.neon
phpstan.neon.dist
postcss.config.js
webpack.config.js
CODE_OF_CONDUCT.md
awk Explicación:
-F/: Usar / como separador de campo de entrada index($0, "/wp-content/themes/") == 1: la línea comienza con /wp-content/themes/ solamente sub(/ .*/, "", $NF): Elimina cualquier cosa después del espacio en el último campo imprimir $NF: Imprimir lcampo ast4
1
¡Guau, esa es una solución elegante! Aunque tendré que leer sobre awk para entender lo que hace XD
-dingo_d27/03/2021 a las 14:49
1
Agregué una explicación en la respuesta
- anubhava27/03/2021 a las 14:52
es posible que desee agregar /wp-content/temas/**/ a la mezcla para abordar el caso en el que .gitattributes contiene referencias a otros directorios (es decir, NF > 2 pero el usuario está interesado en un directorio específico, ¿tal vez enviado a awk a través de -v?)
-markp-fuso27/03/2021 a las 15:04
1
Buen punto @markp-fuso, he modificado mi respuesta
- anubhava27/03/2021 a las 15:08
La solución rápida sería: simplemente canalizar la salida a través de sort -u :-)
La causa principal es el uso del modificador 'p' en la expresión regular sed. Esto imprime las copias adicionales. Puedes omitirlo gnu.org
Si necesita los resultados con un nombre de archivo por línea, yo crearía el script
< "/.gitattributes" awk '
/\/wp-content\/themes\/\*\*\// {
gsub(/\/wp-content\/themes\/\*\*\//,"");
gsub(/ export-ignore/,"");
print 1008611;
}'
o, mejor aún, con awk
1008611