Linux Shell script introduction - splicing with cat + recording and playing back terminal sessions + finding and listing files

Posted by poelinca on Wed, 19 Jan 2022 12:10:02 +0100

1. Splice with cat

cat stands for conCATenate
cat command can read files, splice data, and read from standard input

# 1. Print the contents of a single file
$ cat file.txt
This is a line inside file.txt
This is the second line inside file.txt

# 2. Print the contents of multiple files
$ cat one.txt two.txt
This is a line from one.txt
This is a line from two.tx

# 3. Combine stdin with the data in another file
## -The file name to be used as stdin text
$ echo "Text through stdin" | cat - file.txt

# 4. Compress adjacent blank lines
## You can also use tr to delete all blank lines
$ cat -s file

# 5. Display tabs as ^ I
## Distinguish tabs from contiguous spaces
$ cat -T file

# 6. Display line number
$ cat -n file

# 7. Skip the blank line and display the line number
$ cat -b file

The shell will create a new output file before opening the input file. The cat command does not allow the same file to be used as input and reset output. Using the pipeline and redirecting the output will empty the input file

$ echo "This will vanish" > myfile
$ cat -n myfile > myfile
cat: myfile: input file is output file
$ cat myfile| cat -n > myfile
$ ls -l myfile
-rw-rw-rw . 1 user user 0 AUG 24 00:14 myfile # myfile is an empty file

Record and play back terminal sessions

The script command can record keystrokes and keystroke timing, and save the input and output results in corresponding files. The scriptreplay command plays back a session. However, you cannot record vi, emacs, or other applications that map characters to specific locations on the screen

# 1. Start recording terminal session
$ script -t 2> timing.log -a output.session
## -t. Send the timing information to stdout and redirect stderr to timing.com using 2 > log
# 2. Playback command execution process
$ scriptreplay timing.log output.session

This strategy is not applicable to shells that do not support redirecting stderr to files separately, such as csh shell

Find and list files

find works by traversing down the file hierarchy, matching qualified files and performing corresponding operations. The default operation is to print out files and directories, which can also be specified with the - print option

# Lists all files and subdirectories in a given directory
$ find . -print
$ echo "test" >  "file name"
$ find . -type f -print | xargs ls -l
ls: cannot access ./file: No such file or directory
ls: cannot access name: No such file or directory
$ find . -type f -print0 | xargs -0 ls -l
-rw-rw-rw. 1 user group 5 Aug 24 15:00 ./file name

-The print option uses a newline character to separate each file or directory name that is output
-The print0 option is separated by a null character (\ 0). The main use of - print0 is to pass a file name containing a newline or white space character to the xargs command

The find command can find files based on wildcards or regular expressions, directory tree depth, file date, file type, etc

  1. Search by file name or regular expression
    -name specifies the pattern to be found. This pattern can be a wildcard or a regular expression.

The shell will extend the wildcard without quotation marks or in double quotation marks ("). Single quotation marks can prevent the shell from extending *. txt, so that the string can be passed to the find command intact

-iname ignores letter case
The find command supports logical operators, - a AND - AND options can perform logical AND (AND) operations, AND - o AND - OR options can perform logical OR (OR) operations

$ ls
new.txt some.jpg text.pdf stuff.png
$ find . \( -name '*.txt' -o -name '*.pdf' \) -print
# Print out all txt and pdf file
./text.pdf
./new.txt

$ find . \( -name '*e*' -and -name 's*' \)
# Select a file whose name begins with s and contains e
./some.jpg

-The path option limits the path and name of the matched file

$ find /home/users -path '*/slynux/*' -name '*.txt' -print
/home/users/slynux/readme.txt
# Cannot match / home / users / slynux txt

-The regex option is similar to - path, but - regex matches file paths based on regular expressions
-The iregex option allows regular expressions to ignore case when matching

$ ls
new.py next.jpg test.py script.sh
$ find . -regex '.*\.(py\|sh\)$'
./test.py
script.sh

$ find . -iregex '.*\(\.py\|\.sh\)$'
./test.py
./new.py
./script.sh
  1. Negative parameter
    find can be used! Exclude matching patterns
$ find . ! -name "*.txt" -print

$ ls
list.txt new.PY new.txt next.jpg test.py

$ find . ! -name "*.txt" -print
.
./next.jpg
./test.py
./new.PY
  1. Directory depth based search
    The find command will not follow the symbolic link, and the - L option allows find to follow the symbolic link, but if a link to itself is encountered, the find command will fall into an endless loop

-The maxdepth and - mindepth options limit the depth of the directory traversed by the find command, which prevents the find command from looking up endlessly

/The proc file system contains information about the system and the current task. The directory level of a specific task is quite deep, with some symbolic links around back on themselves. Each process running in the system has a corresponding subdirectory in proc, and its name is the process ID of the process. Under this directory, there is a link called cwd, which points to the current working directory of the process

$ find -L /proc -maxdepth 1 -name 'bundlemaker.def' 2>/dev/null
# -The L option tells the find command to follow symbolic links
# Start searching from the / proc directory
# -maxdepth 1 limits the search to the current directory only
# -name 'bundlemaker.def 'specifies the file to be found
# 2> / dev / null sends error information about circular links to empty devices

-mindepth sets the minimum directory depth at which find starts searching

$ find . -mindepth 2 -name "f*" -print
./dir1/dir2/file1
./dir3/dir4/file2

-Maxdepth and - mindepth should appear early in the find command. As a later option, it may affect the efficiency of find because it has to perform some unnecessary checks. For example, if - maxdepth appears after - type, find will first find the files specified by - type, and then filter out those files that do not meet the specified depth in the matching files. However, if you specify the directory depth before - type, find can check the types of all files that meet the specified depth, which is the most effective way to search

  1. Search by file type
    Unix like systems treat everything as files. Files have different types, such as ordinary files, directories, character devices, block devices, symbolic links, hard links, sockets, FIFO and so on

-The type option filters file searches

$ find . -type d -print
$ find . -type f -print
$ find . -type l -print
file typeType parameter
Ordinary filef
Symbolic linkl
catalogued
Character devicec
Block deviceb
sockets
FIFOp
  1. Search based on the timestamp of the file
    Each file in the Unix/Linux file system has three timestamps
  • Access time (- atime): the time when the user last accessed the file
  • Modification time (- mtime): the time when the file content was last modified
  • Change time (- ctime): the time when file metadata (such as permissions or ownership) was last changed

Unix does not save the creation time of the file by default. But some file systems (ufs2, ext4, zfs, btrfs, jfs) choose to do so. You can use the stat command to access the file creation time

Since some applications modify files by creating a new file first and then deleting the original file, the file creation time may not be accurate

-atime, - mtime, and - ctime can be used as time options for find. You can specify the number of days with an integer value. These numbers can be preceded by - or +- Represents less than, + represents greater than

# 1. Print out all documents accessed in the last 7 days
$ find . -type f -atime -7 -print

# 2. Print out all documents accessed just 7 days ago
$ find . -type f -atime 7 -print

# 3. Print out all documents that have been accessed for more than 7 days
$ find . -type f -atime +7 -print

The find command also supports the option of using "minutes" as the timing unit
These options include

  • -amin
  • -mmin
  • -cmin
# Print out all files accessed 7 minutes ago
$ find. -type f -amin +7 -print

-The newer option can specify a reference file to compare the modification time, and then find all files that are updated (more recent modification time) than the reference file

# Find the ratio file Txt all files that have been modified more recently
$ find . -type f -newer file.txt -print
  1. File size based search
$ find . -type f -size +2k
$ find . -type f -size -2k
$ find . -type f -size 2k

Other file size units
b: Block (512 bytes)
c: Byte
w: Word (2 bytes)
k: Kilobytes (1024 bytes)
M: Megabytes (1024k bytes)
G: Hexbytes (1024M bytes)

  1. Matching based on file permissions and ownership
    -perm permission bit
# Print out a file with permission 644
$ find . -type f -perm 644 -print

# PHP files on the Apache Web server need to have appropriate execution permissions
# Here are the PHP files that do not have execution permissions set
$ find . -type f -name "*.php" ! -perm 644 -print
PHP/custom.php
$ ls -l PHP/custom.php
-rw-rw-rw-. root root 513 Mar 13 2016 PHP/custom.php

-user USER (user name or UID)

$ find . -type f -user slynux -print
  1. Use find to perform the corresponding operation

1) Delete matching files
The delete option of the find command can delete the matched file

$ find . -type f -name "*swp" -delete
  1. Execute command
    With the - exec option, the find command can be used in conjunction with other commands
$ find . -type f -user root -exec chown slynux {} \;

You must execute the find command as root to change the ownership of a file or directory
The find command uses a pair of curly braces {} for the file name
In the following example, for each matching file, the find command replaces {} with the corresponding file name and changes the ownership of the file. If find finds two files owned by root, it changes its owner to slynux

Note the \; at the end of the command; The semicolon must be escaped, otherwise the shell will treat it as the end of the find command, not the end of the chown command
For each matching file call, it costs a lot. If the specified command can accept multiple parameters (such as chown), you can use the plus sign (+) as the end of the command. In this way, find will generate a list containing all search results, and then execute it as the parameter of the specified command at one time

$ find . -type f -name '*.c' -exec cat {} \; > all_c_files.txt
$ find . -type f -name '*.c' -exec cat {} > all_c_files.txt \;
$ find . -type f -name '*.c' -exec cat {} > all_c_files.txt +

Redirect data from find to all using the > operator_ c_ files. Txt file. The reason why > > (append) is not used is that there is only one data stream for all the output of the find command. It is necessary to use > > only when multiple data streams are appended to a single file

$ find . -type f -mtime +10 -name "*.txt" -exec cp {} OLD \;

You cannot directly use multiple commands in the - exec option. This option can only accept a single command, but you can write multiple commands to a shell script and then use this script in - exec

-exec ./commands.sh {} \;

-exec can be used with printf to generate output information

$ find . -type f -name "*txt" -exec printf "Text file: %s\n" {} \;
Config file: /etc/openvpn/easy-rsa/openssl-1.0.0.cnf
Config file: /etc/my.cnf
  1. Let find skip a specific directory
    Skipping some subdirectories during find execution can improve performance
    The technique of excluding certain files or directories when searching is called pruning
$ find devel/source_path -name '.git' -prune -o -type f -print
# -name '. git '- prune is the part of the command responsible for pruning, which indicates git directory should be excluded
# -type f -print describes the operation to be performed