"7z a" should (perhaps) allow filename completion
Describe the feature/solution
I often create 7z files based on the filename(s) that I'm putting in there. For example, let's say I have these files: blah.data, blah.log, blah.whatever. From them, I want to create blah.7z.
Before I installed bash-completion, the way I would typically do that would be to type 7z a , hit tab, add 7z , hit tab again, and add .*, resulting in the command 7z a blah.7z blah.*. Unfortunately (at least for me), bash-completion does nothing when I hit tab the first time (i.e. after 7z a ). I think it would be nice if it allowed filename completion, so as to keep the standard behavior available instead of just removing it entirely.
Maintenance (please complete the following information)
- [ ] This is a request for new completion
- [ ] Link to upstream project query about shipping the completion:
These are kind of difficult corner cases to handle. If we supported arbitrary filename completions directly after a, we'd be knowingly generating completions that are certain to be incorrect, and I don't personally like that practice. I think we only have one exception to that "rule" in the tree -- I don't remember exactly what it was, but it was such a common case that we eventually did it.
This, on the other hand, my gut says is not such a common usage scenario, so I'm inclined not to do it. There are a couple of things you can do though instead of disabling the completion completely. I appreciate not any of them may be perfect for your use case, but I thought I'd mention them just in case:
-
$BASH_COMPLETION_FILEDIR_FALLBACK - The first and second FAQ items:
M-/, or overriding rather than removing the completion function shipped by us.
Thanks, I'll take a look at the workarounds. I am not sure that I'm understanding the objection, though: It seems to me that you'd be generating completions that are certain to be incorrect only if the user hit "tab" and didn't mean to.
EDIT: And even in that case, you wouldn't be "knowingly" generating completions are certain to be incorrect.
For example:
mkdir /tmp/foo
cd /tmp/foo
touch bar
7z a <TAB>
If we complete that to bar (and append a space which is what typically happens for filename completions), we have knowingly produced an invalid completion -- bar is not valid argument for a there, no matter if tab was hit intentionally or not.
Why not?
[170206 bob@iron 1;~]$ mkdir tmp1 tmp2
[170211 bob@iron 1;~]$ echo "blah" > tmp1/tmpblah
[170222 bob@iron 1;~]$ cd tmp2
[170226 bob@iron 1;~/tmp2]$ touch bar
[170232 bob@iron 1;~/tmp2]$ 7z a bar ../tmp1/tmpblah
7-Zip (z) 24.09 (x64) : Copyright (c) 1999-2024 Igor Pavlov : 2024-11-29
64-bit locale=C.UTF-8 Threads:8 OPEN_MAX:1885104
Scanning the drive:
1 file, 5 bytes (1 KiB)
Creating archive: bar.7z
Add new data to archive: 1 file, 5 bytes (1 KiB)
Files read from disk: 1
Archive size: 131 bytes (1 KiB)
Everything is Ok
[170254 bob@iron 1;~/tmp2]$ ls -l
total 1
-rw-r--r-- 1 bob bob 0 Apr 20 17:02 bar
-rw-r--r-- 1 bob bob 131 Apr 20 17:02 bar.7z
[170258 bob@iron 1;~/tmp2]$ 7z x bar.7z
7-Zip (z) 24.09 (x64) : Copyright (c) 1999-2024 Igor Pavlov : 2024-11-29
64-bit locale=C.UTF-8 Threads:8 OPEN_MAX:1885104
Scanning the drive for archives:
1 file, 131 bytes (1 KiB)
Extracting archive: bar.7z
--
Path = bar.7z
Type = 7z
Physical Size = 131
Headers Size = 122
Method = LZMA2:12
Solid = -
Blocks = 1
Everything is Ok
Size: 5
Compressed: 131
[170309 bob@iron 1;~/tmp2]$ ls
bar bar.7z tmpblah
[170310 bob@iron 1;~/tmp2]$ ls tmpblah
tmpblah
[170314 bob@iron 1;~/tmp2]$ cat tmpblah
blah
[170319 bob@iron 1;~/tmp2]$
Ouch, now that's weird/magical/unexpected behavior to me. --help or man page do not seem to offer any explanation for it. But given that, I'm willling to reconsider, given submitted PR along with a bunch of test cases that confirm it's the intended behavior.
Yeah, honestly I didn't expect it to put ".7z" on automatically, but what I actually did expect was that it would just allow "bar" to be a 7z file (not "a file with a 7z extension"). And in that case, it would make sense too, since 7z allows you to extract such a file anyway:
[220620 bob@iron 1;~/tmp]$ echo "foo" > bar
[220627 bob@iron 1;~/tmp]$ 7z a bar.7z bar
7-Zip (z) 24.09 (x64) : Copyright (c) 1999-2024 Igor Pavlov : 2024-11-29
64-bit locale=C.UTF-8 Threads:8 OPEN_MAX:1885104
Scanning the drive:
1 file, 4 bytes (1 KiB)
Creating archive: bar.7z
Add new data to archive: 1 file, 4 bytes (1 KiB)
Files read from disk: 1
Archive size: 122 bytes (1 KiB)
Everything is Ok
[220639 bob@iron 1;~/tmp]$ mv bar.7z zipped
[220650 bob@iron 1;~/tmp]$ rm bar
[220718 bob@iron 1;~/tmp]$ 7z x zipped
7-Zip (z) 24.09 (x64) : Copyright (c) 1999-2024 Igor Pavlov : 2024-11-29
64-bit locale=C.UTF-8 Threads:8 OPEN_MAX:1885104
Scanning the drive for archives:
1 file, 122 bytes (1 KiB)
Extracting archive: zipped
--
Path = zipped
Type = 7z
Physical Size = 122
Headers Size = 114
Method = LZMA2:12
Solid = -
Blocks = 1
Everything is Ok
Size: 4
Compressed: 122
[220724 bob@iron 1;~/tmp]$ cat bar
foo
[220736 bob@iron 1;~/tmp]$
Lots of programs are like this, especially in the *nix world. They don't really care about extensions. Maybe there's a common, suggested, or even default extension, but it's not required.
Sure, extensions aren't often that interesting. But what I find very surprising, non-unixy, and directly against the tool's own usage message and man page is the behavior of 7z a foo when a file foo is present: it creates a foo.7z and puts foo in it (or adds foo in the archive if it was already present). But the usage message says
Usage: 7z <command> [<switches>...] <archive_name> [<file_names>...] [@listfile]
...and the man page says
7z command [switches...] archive_name [file_names] [@listfile]
...i.e. archive_name is a mandatory argument, and my foo should have been treated as that. Instead, the tool did not treat it as archive_name but a file_name and came up with an archive_name on its own. I understand it tries to "DWIM", but it would be better if the documentation matched reality.
[170226 bob@iron 1;~/tmp2]$ touch bar [170232 bob@iron 1;~/tmp2]$ 7z a bar ../tmp1/tmpblah ... [170309 bob@iron 1;~/tmp2]$ ls bar bar.7z tmpblah[...]
Sure, extensions aren't often that interesting. But what I find very surprising, non-unixy, and directly against the tool's own usage message and man page is the behavior of 7z a foo when a file foo is present:
I think the above code example was a bit confusing. The 7z a bar creates bar.7z regardless of the existence of the file bar. In my environment (Fedora 41),
$ ls
$ 7za a non-existent
7-Zip (a) [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=ja_JP.UTF-8,Utf16=on,HugeFiles=on,64 bits,8 CPUs Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz (906E9),ASM,AES-NI)
Scanning the drive:
0 files, 0 bytes
Creating archive: non-existent.7z
Items to compress: 0
Files read from disk: 0
Archive size: 32 bytes (1 KiB)
Everything is Ok
$ ls
non-existent.7z
So this behavior couldn't be a reason to specifically generate the filenames because the argument can be an arbitrary string.
The expectation behind the suggested fallback filename completion would be simply that we may want to name a new file similar to existing ones. Making it a habit to press M-/ in this kind of situation seems a good idea to me.
Lots of programs are like this, especially in the *nix world.
I agree that filenames can have an arbitrary name (and the filename extension doesn't matter) with Unix programs. However, automatically suffixing .7z feels non-Unixy. It comes from MS-DOS/Windows. 7-Zip is originally a Windows application. I'm not aware of many Unix programs that automatically add the filename extension; I know the TeX toolset does it somehow, but I feel it tries to form its own ecosystem (which is slightly different from the Unix world).
However, automatically suffixing .7z feels non-Unixy
I agree; like I said, I was surprised by it. But it's not really important to my immediate point, which is that this "invalid argument" argument doesn't seem to apply. It's not an invalid argument, and even if it didn't do this weird "append an extension" thing, it still wouldn't be an invalid argument.
But more importantly, to me, at least, my main point is summed up by what you said in your earlier comment:
The expectation behind the suggested fallback filename completion would be simply that we may want to name a new file similar to existing ones.
This is exactly the behavior I requested in this issue. It's default bash functionality that I used very often before I installed bash-completion, and I can't imagine I'm the only one.
Making it a habit to press M-/ in this kind of situation seems a good idea to me.
Thanks, I'll try it out. I was unaware of it.
Here, by the way, is an example of an actual invalid argument which bash-completion has no issue with:
[112233 bob@iron 1;~]$ mkdir tmp1
[112239 bob@iron 1;~]$ cd tmp1/
[112241 bob@iron 1;~/tmp1]$ touch blah
[112243 bob@iron 1;~/tmp1]$ echo "cp<space><tab><tab>"
cp<space><tab><tab>
[112247 bob@iron 1;~/tmp1]$ cp blah blah
cp: blah and blah are identical (not copied).
[112249 bob@iron 1;~/tmp1]$
Of course, that's fairly silly as it is, but it's actually useful (with slight modification) in the same way as with my 7z suggestion:
[112726 bob@iron 1;~/tmp1]$ echo "cp<space><tab><tab><backspace>.bak"
cp<space><tab><tab><backspace>.bak
[112755 bob@iron 1;~/tmp1]$ cp blah blah.bak
[112801 bob@iron 1;~/tmp1]$
I do this sort of thing a lot - i.e. not just with 7z, but in many situations with many commands.
actual invalid argument which bash-completion has no issue with
bash-completion might not at the moment, but I do -- I've had the intent to address this class of issues for a long time (there's a lot of it across the tree) but haven't got around to it yet. It doesn't mean we should knowingly continue the practice when we can sanely avoid it.
There was a duplicate request at #1384, which was about the fallback filename completion for the general command.