File: save.py 1 #!/usr/bin/python 2 3 # The MIT License (MIT) 4 # 5 # Copyright (c) 2026 pacman64 6 # 7 # Permission is hereby granted, free of charge, to any person obtaining a copy 8 # of this software and associated documentation files (the "Software"), to deal 9 # in the Software without restriction, including without limitation the rights 10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 # copies of the Software, and to permit persons to whom the Software is 12 # furnished to do so, subject to the following conditions: 13 # 14 # The above copyright notice and this permission notice shall be included in 15 # all copies or substantial portions of the Software. 16 # 17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 # SOFTWARE. 24 25 26 from itertools import islice 27 from sys import argv, exit, stderr, stdin, stdout 28 29 30 info = ''' 31 save [options...] [filepaths...] 32 33 This script reads all bytes from the standard input, and only after that 34 saves those data to the file given. Nothing is saved when not given any 35 filenames. 36 37 A single dash used as a name refers to the standard output, and can be 38 used more than once. 39 40 All (optional) leading options start with either single or double-dash: 41 42 -a, -append append/extend (instead of replace) existing file-data 43 -h, -help show this help message 44 ''' 45 46 # a leading help-option arg means show the help message and quit 47 if len(argv) > 1 and argv[1] in ('-h', '--h', '-help', '--help'): 48 print(info.strip()) 49 exit(0) 50 51 skip = 1 52 output_mode = 'wb' 53 for s in islice(argv, 1, None): 54 if s == '-': 55 break 56 57 if s == '--': 58 skip += 1 59 break 60 61 if s in ('-a', '--a', '-append', '--append'): 62 output_mode = 'ab' 63 skip += 1 64 continue 65 66 if s.startswith('-'): 67 print(f'save: unsupported option {s}', file=stderr) 68 exit(1) 69 70 break 71 72 if len(argv) <= skip: 73 print(info.strip(), file=stderr) 74 exit(1) 75 76 try: 77 data = stdin.buffer.read() 78 for name in islice(argv, skip, None): 79 if name == '-': 80 stdout.buffer.write(data) 81 continue 82 with open(name, output_mode) as out: 83 out.write(data) 84 except KeyboardInterrupt: 85 exit(2) 86 except Exception as e: 87 print(str(e), file=stderr) 88 exit(1)