Intentando agregar todos los archivos del directorio actual para archivar y nombrar el archivo de salida de acuerdo con un nombre/extensión de archivo específico que se agregó.
Básicamente, cuando se agrega un archivo con una extensión .exe, me gustaría que el nombre del archivo sea el mismo que el de ese archivo, asumiendo que solo hay uno y al menos un .exe.
Foo.exe -> Foo.7z
Aquí está el guión que tengo hasta ahora. 7z a archive.7z *.* -x!*.sh
Respuesta1
set -- *.exe
almacena nombres de archivos que coinciden *.exe
como parámetros posicionales, a menos que no haya coincidencias. En caso de que no haya coincidencia, el resultado depende del shell (ver el comienzo deesta respuesta); en el shell POSIX obtienes la *.exe
cadena literal como primer y único parámetro posicional.
Si está seguro de que hay exactamente una coincidencia, no necesita probar nada. Si no estás seguro entonces:
- compruebe si
$#
se expande a1
([ "$#" -eq 1 ]
), - comprobar si el supuesto archivo existe (
[ -e "$1"]
).
Entonces el nombre que buscas está en $1
. Para traducir Foo.exe
necesitasFoo.7z
eliminarexe
y añadir 7z
( ${1%exe}7z
).
El fragmento será como:
(
set -- *.exe
# here validate $# and/or $1 if necessary
7z a "${1%exe}7z" …
)
Utilicé un subshell, por lo que set
no afecta los parámetros posicionales del shell principal.Citar es importante.
Notas:
- La solución permite que la coincidencia sea un directorio.Cualquier directorio también es un archivo..
- Escribiste "agregar todos los archivos" y luego usaste
*.* -x!*.sh
. No voy a ser quisquilloso diciendo que la exclusión contradice "todos los archivos". Sin embargo, hay problemas:-x!*.sh
debe estar entrecomillado, para que el shell nunca se expanda*
. La cadena debe estar entre comillas simples porque algunos shells se expanden!
incluso entre comillas dobles.*.*
puede significar "todos los archivos" en Windows (al menoscon algunas herramientas), pero en un shell de Linux el punto coincide estrictamente con un punto.*
como patrón de generación de nombres de archivos está más cerca de "todos los archivos",todavía no "todos los archivos".
- La solución es propensa aTOCTOU. Probablemente el contenido de su directorio no cambie "al azar" y la solución funcionará. Si el directorio no es estático, es posible que sea necesario crear un archivo con un nombre temporal, enumerar su contenido y analizarlo para saber qué
.exe
(si lo hay) llegó al archivo y, finalmente, cambiar el nombre del archivo en consecuencia. - Tenga en cuenta que los nombres de archivos en Linux distinguen entre mayúsculas y minúsculas en general; Las herramientas que funcionan con nombres de archivos también distinguen entre mayúsculas y minúsculas. Normalmente
set -- *.exe
no lo detectaFOO.EXE
. En algunos shells puedes ajustar este comportamiento (por ejemplo, investigarshopt -s nocaseglob
en Bash); entonces querrás utilizarlo${1%[eE][xX][eE]}7z
para tratar correctamenteEXE
oExe
cualquier otra variante durante la traducción de nombres.