0

Trying to add all files from current directory to archive and name the output file according to a specific file name/extension that was added.

Essentially when there is a file thats being added with a .exe extension, id like the archive name to be the same as that file, assuming there is only one and at least one .exe.

Foo.exe -> Foo.7z

Heres the script i have so far 7z a archive.7z *.* -x!*.sh

Trebrick
  • 3
  • 3

1 Answers1

0

set -- *.exe stores filenames matching *.exe as positional parameters, unless there is no match. In case there is no match the result depends on the shell (see the beginning of this answer); in the POSIX shell you get the literal *.exe string as the first and only positional parameter.

If you are sure there is exactly one match then you don't need to test anything. If you are not sure then:

  • check if $# expands to 1 ([ "$#" -eq 1 ]),
  • check if the alleged file exists ([ -e "$1"]).

Then the name you're after is in $1. To translate Foo.exe to Foo.7z you need to remove exe and add 7z (${1%exe}7z).

The snippet will be like:

(
set -- *.exe
# here validate $# and/or $1 if necessary
7z a "${1%exe}7z" …
)

I used a subshell, so set does not affect the positional parameters of the main shell. Quoting is important.


Notes:

  • The solution allows the match to be a directory. Any directory is also a file.
  • You wrote "add all files" and then used *.* -x!*.sh. I'm not going to nitpick by saying the exclusion contradicts "all files". There are problems though:
    • -x!*.sh should be quoted, so the shell never expands *. The string should be single-quoted because some shells expand ! even in double-quotes.
    • *.* may mean "all files" in Windows (at least with some tools), but in a Linux shell the dot strictly matches a dot. * as a filename generation pattern is closer to "all files", still not "all files".
  • The solution is prone to TOCTOU. Probably the content of your directory does not change "randomly" and the solution will work. If the directory is not static then one may need to create an archive with temporary name, list its contents and parse to learn what .exe (if any) got to the archive, finally rename the archive accordingly.
  • Keep in mind filenames in Linux are case-sensitive in general; tools that work with filenames are also case-sensitive. Normally set -- *.exe does not detect FOO.EXE. In some shells you can adjust this behavior (e.g. investigate shopt -s nocaseglob in Bash); then you would want to use ${1%[eE][xX][eE]}7z to properly deal with EXE, Exe or any other variant during name translation.
Kamil Maciorowski
  • 69,815
  • 22
  • 136
  • 202
  • Can this be done recursively? Should i create a new post/question? – Trebrick Jul 28 '21 at 07:34
  • @Trebrick Mind [this](https://meta.stackexchange.com/q/43478/355310), although I don't think the request crosses the line. So it's up to you. If you choose to add the requirement to the current question then please unaccept my answer (because it doesn't fully address the new scope). Or you can create a new question. In this case you may link to the above one to provide the context (but keep the new question standalone regardless). In any case I think I will be able to help, but not in the next several hours. Others may help sooner. I will get back to your question(s) and respond if they don't. – Kamil Maciorowski Jul 28 '21 at 07:48