Special Characters
-
bash$ cat - abc abc ... Ctl-DAs expected, cat - echoes stdin, in this case keyboarded user input, to stdout. But, does I/O redirection using - have real-world applications?
(cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -) # Move entire file tree from one directory to another # [courtesy Alan Cox <a.cox@swansea.ac.uk>, with a minor change] # 1) cd /source/directory # Source directory, where the files to be moved are. # 2) && # "And-list": if the 'cd' operation successful, # then execute the next command. # 3) tar cf - . # The 'c' option 'tar' archiving command creates a new archive, # the 'f' (file) option, followed by '-' designates the target file # as stdout, and do it in current directory tree ('.'). # 4) | # Piped to ... # 5) ( ... ) # a subshell # 6) cd /dest/directory # Change to the destination directory. # 7) && # "And-list", as above # 8) tar xpvf - # Unarchive ('x'), preserve ownership and file permissions ('p'), # and send verbose messages to stdout ('v'), # reading data from stdin ('f' followed by '-'). # # Note that 'x' is a command, and 'p', 'v', 'f' are options. # # Whew! # More elegant than, but equivalent to: # cd source/directory # tar cf - . | (cd ../dest/directory; tar xpvf -) # # Also having same effect: # cp -a /source/directory/* /dest/directory # Or: # cp -a /source/directory/* /source/directory/.[^.]* /dest/directory # If there are hidden files in /source/directory.
bunzip2 -c linux-2.6.16.tar.bz2 | tar xvf - # --uncompress tar file-- | --then pass it to "tar"-- # If "tar" has not been patched to handle "bunzip2", #+ this needs to be done in two discrete steps, using a pipe. # The purpose of the exercise is to unarchive "bzipped" kernel source.Note that in this context the "-" is not itself a Bash operator, but rather an option recognized by certain UNIX utilities that write to stdout, such as tar, cat, etc.
bash$ echo "whatever" | cat - whateverWhere a filename is expected, - redirects output to stdout (sometimes seen with tar cf), or accepts input from stdin, rather than from a file. This is a method of using a file-oriented utility as a filter in a pipe.
By itself on the command-line, file fails with an error message.
bash$ file Usage: file [-bciknvzL] [-f namefile] [-m magicfiles] file...Add a "-" for a more useful result. This causes the shell to await user input.
Now the command accepts input from stdin and analyzes it.
bash$ file - abc standard input: ASCII text bash$ file - #!/bin/bash standard input: Bourne-Again shell script text executableThe "-" can be used to pipe stdout to other commands. This permits such stunts as prepending lines to a file.
Using diff to compare a file with a section of another:
grep Linux file1 | diff file2 -
Finally, a real-world example using - with tar.
Example 3-4. Backup of all files changed in last day
#!/bin/bash # Backs up all files in current directory modified within last 24 hours #+ in a "tarball" (tarred and gzipped file). BACKUPFILE=backup-$(date +%m-%d-%Y) # Embeds date in backup filename. # Thanks, Joshua Tschida, for the idea. archive=${1:-$BACKUPFILE} # If no backup-archive filename specified on command-line, #+ it will default to "backup-MM-DD-YYYY.tar.gz." tar cvf - `find . -mtime -1 -type f -print` > $archive.tar gzip $archive.tar echo "Directory $PWD backed up in archive file \"$archive.tar.gz\"." # Stephane Chazelas points out that the above code will fail #+ if there are too many files found #+ or if any filenames contain blank characters. # He suggests the following alternatives: # ------------------------------------------------------------------- # find . -mtime -1 -type f -print0 | xargs -0 tar rvf "$archive.tar" # using the GNU version of "find". # find . -mtime -1 -type f -exec tar rvf "$archive.tar" '{}' \; # portable to other UNIX flavors, but much slower. # ------------------------------------------------------------------- exit 0
Filenames beginning with "-" may cause problems when coupled with the "-" redirection operator. A script should check for this and add an appropriate prefix to such filenames, for example ./-FILENAME, $PWD/-FILENAME, or $PATHNAME/-FILENAME.
If the value of a variable begins with a -, this may likewise create problems.
var="-n" echo $var # Has the effect of "echo -n", and outputs nothing.
混了那麼多年,現在才知道原來 - (dash) 是這樣用的… Orz
