List Methods: join()
The central join() operation is small but important: it converts several source-path strings into one space-separated string that can become part of the command passed to os.system().
From Manual Backups to Automation
Backing up files manually is tedious and error-prone. You might forget a directory, overwrite an earlier backup, or use an inconsistent filename. A Python backup program automates the process by selecting source directories, creating a timestamped archive name, assembling a zip command, and executing that command.
The central join() operation is small but important: it converts several source-path strings into one space-separated string that can become part of the command passed to os.system().
What do you think happens?
The source list contains two paths. What should the command fragment look like after joining the list with a single space?
Reveal answer
/home/user/docs /home/user/photos
The expression ' '.join(source) places one space between the list items and returns one string.
Joining Command Components
Suppose source is a list containing the directories to back up. The expression ' '.join(source) uses a space as the separator and returns one string containing every source item in list order. For example, if source contains '/home/user/docs' and '/home/user/photos', the result is '/home/user/docs /home/user/photos'. The list remains useful while Python is selecting the sources; join() creates the single text fragment needed when the command is assembled.
Two Sources Become One Command Fragment
Combine two source directories so they can be inserted into a zip command.
- 1Start with the list
The source list contains '/home/user/docs' and '/home/user/photos'.
- 2Choose the separator
The string ' ' is the separator, so
join()places one space between the items. - 3Apply join()
The expression ' '.join(source) produces '/home/user/docs /home/user/photos'.
- 4Use the result
That one string becomes the source portion of the command assembled for
os.system().
/home/user/docs /home/user/photos
Portable Archive Names
The program builds the target archive filename in stages. It combines the backup directory, os.sep, a timestamp, and the .zip extension. os.sep supplies the directory separator for the operating system: a backslash on Windows and a forward slash on macOS and Linux. This avoids hardcoding one operating system's separator.
The timestamp comes from time.strftime(). The format string '%Y%m%d%H%M%S' represents year, month, day, hour, minute, and second. A resulting name can look like 20240115143022.zip. The timestamp is inserted between the backup directory and the .zip extension, giving the archive a name based on when it was created.
From Python to the Shell
After the target filename is ready, the program constructs the full zip command as a string. The command combines the zip utility, options, the target archive, and the joined source list. The -r option tells zip to work recursively through subdirectories. The format() method supplies the target and joined sources for the command's placeholders.
import os
import time
source = ["/home/user/docs", "/home/user/photos"]
target_dir = "/home/user/backups"
timestamp = time.strftime("%Y%m%d%H%M%S")
target = target_dir + os.sep + timestamp + ".zip"
command = "zip -r {0} {1}".format(target, " ".join(source))
print(command)
result = os.system(command)
if result == 0:
print("Backup succeeded")
else:
print("Backup failed")- 1Python stores the source directories in a list.
- 2Python creates a timestamp and combines it with the target directory and .zip extension.
- 3The
join()call creates one string containing the source directories separated by spaces. - 4
format()constructs the complete zip command. - 5
print()displays the command before execution. - 6
os.system()passes the command to the operating system as if it had been typed in a terminal or command prompt. - 7The program compares the returned value with zero and prints a success or failure message.
- source is a list of directories to back up.
os.sepsupplies the operating system's directory separator.strftime()creates the timestamp text.join()turns the source list into one space-separated string.format()inserts the target and joined sources into the command.os.system()executes the command through the operating system shell.
The printed command contains zip -r, the timestamped target path, and the two source paths. The later message depends on the integer returned by os.system().| Return value | Program interpretation |
|---|---|
| 0 | The zip command succeeded; print the success message. |
| Non-zero integer | The zip command failed; print the failure message. |
The backup program interprets the value returned by os.system().
Mistakes Beginners Make
Common mistake Passing the source list directly into the command instead of joining it.
What it looks likecommand = "zip -r {0} {1}".format(target, source)Why it failsThe command needs the source list represented as one command string with spaces between its items.
Do this insteadUse " ".join(source) before inserting the sources into the command.
Common mistake Hardcoding one directory separator.
What it looks liketarget = target_dir + "/" + timestamp + ".zip"Why it failsThe source emphasizes that Windows uses a backslash while macOS and Linux use a forward slash.
Do this insteadUse target_dir + os.sep + timestamp + ".zip".Common mistake Treating every os.system() return value as success.
What it looks likeos.system(command) print("Backup succeeded")Why it failsThe command may return a non-zero error code.
Do this insteadStore the returned value and compare it with zero before reporting success.
Common mistake Using a fixed archive filename.
What it looks liketarget = target_dir + os.sep + "backup.zip"Why it failsA fixed name does not provide the timestamped naming scheme used by the backup program.
Do this insteadCreate the timestamp with time.strftime() and place it before the .zip extension.
Customize source and target_dir for your own system before running the program. The source material shows both Windows and Unix-style path examples, so choose paths appropriate to the operating system where the program will run.
Practice the Trace
Assume source contains two directories and target_dir identifies the backup directory. Trace these operations in order: create the timestamp, build target with os.sep, join source with a space, construct the zip command, call os.system(), and interpret the returned value. Write down the value of each major string before moving to the next step.
Hints
- The timestamp format is '%Y%m%d%H%M%S'.
- The joined source string has one space between the source paths.
- A return value of 0 means success; a non-zero value means failure.
- 1Identify the source list and the target directory.
- 2Use
time.strftime()to create the timestamp text. - 3Use
os.sepwhen combining the target directory and timestamped filename. - 4Use ' '.join(source) to create the source portion of the command.
- 5Use
format()to combine the zip utility, options, target, and joined sources. - 6Pass the command to
os.system(). - 7Compare the returned value with zero and report success or failure.
The Complete Mental Model
- 1
join()turns the list of source directories into one space-separated string for the command. - 2
os.sepkeeps the target path aligned with the operating system's directory separator. - 3
time.strftime()creates a timestamped archive name using date and time format codes. - 4
format()assembles the zip command, andos.system()sends it to the operating system shell. - 5The returned value is checked: zero indicates success, while a non-zero error code indicates failure.
Key Takeaways
- Use ' '.join(source) when a list of source paths must become one space-separated command fragment.
- Build portable archive paths with
os.sepinstead of hardcoding a separator. - Use
time.strftime()to place year, month, day, and time information in the archive filename. - Trace the command from Python through
os.system()to the zip utility and back to the returned integer. - Treat 0 as success and a non-zero return value as failure.