Scheduled file copies or directory sync from local directory to FTP server

If you have a remote FTP server that you need to put files into, and you don’t want to deal with SCP/SFTP passkeys, lftp (http://lftp.yar.ru/) on the local client machine might be for you. It comes with most linux distros (I found it using yum simply as lftp) and one of its most useful traits is to be able to mirror the remote FTP directory to your local one, and vice versa (through –reverse mirror). Here’s some examples:

# verbosely mirror files from FTP server to local dir. -d to show FTP responses
lftp -d -u ftpusername,password -e “mirror –only-newer –verbose /home/ftpusername/tmp /home/localusername/tmp” ftphost.com&

# more quietly mirror files *to* FTP server from local dir.
lftp -u ftpusername,password -e “mirror –reverse –only-newer /home/localusername/tmp tmp” ftphost.com&

Notice the ampersand, which sends the command to the background so you don’t have to keep the terminal window open.

Here are some more links:

http://www.softpanorama.org/Net/Application_layer/Ftp/lftp.shtml
http://www.linux.com/archive/articles/122169
http://how-to.wikia.com/wiki/How_to_use_lftp_as_a_sftp_client
http://www.gsp.com/cgi-bin/man.cgi?section=1&topic=lftp

Using screen in Linux to save your bacon

Tonight I’m being plagued by dropped ssh connections. 2 minutes of work, them bam everything goes away. I’ve seen screen used in the past, but never had to use its power until tonight. Ask any seasoned sysadmin and they’ll tell you that screen has saved their bacon many times, and it did for me tonight. I’m definitely adding it to my toolbelt. Hopefully it stays around a little longer.

From http://www.rackaid.com/resources/linux-screen-tutorial-and-how-to/

Linux Screen Tutorial and How To

Posted by Jeff H. 01/01/2008

Using Linux Screen for Session Management

Lost your shell connection? Need multiple shell sessions?

You are logged into your remote server via SSH and happily plucking along at your keyboard and then it happens. Suddenly, the characters stop moving and then you get the dreaded “Connection Closed” message. You have just lost your session. You were halfway through some task and now you have to start over. Ugh. Well you can prevent this from happening by using screen. The Linux screen tool can not only save you from disconnection disasters, but it also can increase your productivity by using multiple windows within one SSH session.

Linux Screen for Session Management!

Screenshot of Linux Screen Terminal

Linux Screen showing the GNU page for Linux Screen Itself

Linux Screen Can Save you from that Lost Connection

What is Screen for Linux?

As the man page states, “Screen is a full-screen window manager that multiplexes a physical terminal between several processes (typically interactive shells).” This can be a life saver when working on your dedicated server. Screen has a several great features for helping you administer your server more productively and safely. I am going to discuss the three features (multiple windows, logging, sessions) that I use the most but be sure to see the man page for full details.

Installing Screen on Linux

Chances are that you already have screen on your system. On most Red Hat distributions you can find it in /usr/bin/screen. To see if screen is in your path, you can use the which command:

[admin@ensim admin]$ which screen

If you do not have screen, then you can install it easily from an RPM or the package file for your system. On Cobalt Raq servers, you can safely use the RedHat RPMS appropriate for your system.
Screen RPMs: rpmfind
Screen Web site: GNU Screen

As you probably already have screen or can use an RPM, I am not going to cover the building of screen from source. Lets get on to how to use screen.

Using Screen

Screen is started from the command line just like any other command:

[admin@gigan admin]$ screen

You may or may not get a text message about screen. If you do not, then you probably think nothing has happened, but it has. You are now inside of a window within screen. This functions just like a normal shell except for a few special characters. Screen uses the command “Ctrl-A” as a signal to send commands to screen instead of the shell. To get help, just use “Ctrl-A” then “?”. You should now have the screen help page.

Screen key bindings, page 1 of 2.

               Command key:  ^A   Literal ^A:  a
break      ^B b       lockscreen ^X x       reset      Z
clear      C          log        H          screen     ^C c
colon      :          login      L          select     " '
copy       ^[ [       meta       a          silence    _
detach     ^D d       monitor    M          split      S
digraph    ^V         next       ^@ ^N sp n suspend    ^Z z
displays   *          number     N          time       ^T t
fit        F          only       Q          title      A
flow       ^F f       other      ^A         vbell      ^G
focus      ^I         pow_break  B          version    v
help       ?          pow_detach D          width      W
history            prev       ^P p ^?    windows    ^W w
info       i          readbuf    <          wrap       ^R r
kill       K          redisplay  ^L l       writebuf   >
lastmsg    ^M m       remove     X          xoff       ^S s
license    ,          removebuf  =          xon        ^Q q
                 [Press Space for next page; Return to end.]

Key bindings are the commands the screen accepts after you hit “Ctrl-A”. You can reconfigure these keys to your liking using a .screenrc file, but I just use the defaults.

Multiple Windows

Screen, like many windows managers, can support multiple windows. This is very useful for doing many tasks at the same time without opening new sessions. As a systems manager, I often have four or five SSH sessions going at the same time. In each of the shell, I may be running two or three tasks. Without screen, that would require 15 SSH sessions, logins, windows, etc. With screen, each system gets its own single session and I use screen to manage different tasks on that system.

To open a new window, you just use “Ctrl-A” “c”. This will create a new window for you with your default prompt. For example, I can be running top and then open a new window to do other things. Top stays running! It is still there. To try this for yourself, start up screen and then run top. (Note: I have truncated some screens to save space.)

Start top

  Mem:   506028K av,  500596K used,    5432K free,
    0K shrd,   11752K buff
    Swap: 1020116K av,   53320K used,  966796K free
              393660K cached
     PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %ME
     6538 root      25   0  1892 1892   596 R    49.1  0.3
     6614 root      16   0  1544 1544   668 S    28.3  0.3
     7198 admin     15   0  1108 1104   828 R     5.6  0.2

Now open a new window with “Ctrl-A” “c”

[admin@ensim admin]$

To get back to top, use “Ctrl-A “n”

   Mem:   506028K av,  500588K used,    5440K free,
    0K shrd,   11960K buff
    Swap: 1020116K av,   53320K used,  966796K free
              392220K cached
     PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %ME
     6538 root      25   0  1892 1892   596 R    48.3  0.3
     6614 root      15   0  1544 1544   668 S    30.7  0.3

You can create several windows and toggle through them with “Ctrl-A” “n” for the next window or “Ctrl-A” “p” for the previous window. Each process will keep running while your work elsewhere.

Leaving Screen

There are two ways to get out of screen. The first is just like logging out of a shell. You kill the window with “Ctrl-A” “K” or “exit” will work on some systems. This will kill the current windows. If you have other windows, you will drop into one of those. If this is the last window, then you will exit screen.

The second way to leave screen is to detach from a windows. This method leaves the process running and simple closes the window. If you have really long processes, you need to close your SSH program, you can detach from the window using “Ctrl-A” “d”. This will drop you into your shell. All screen windows are still there and you can re-attach to them later.

Attaching to Sessions

So you are using screen now and compiling that program. It is taking forever and suddenly your connection drops. Don’t worry screen will keep the compilation going. Login to your system and use the screen listing tool to see what sessions are running:

[root@gigan root]# screen -ls
There are screens on:
        31619.ttyp2.gigan       (Detached)
        4731.ttyp2.gigan        (Detached)
2 Sockets in /tmp/screens/S-root.

Here you see I have two different screen sessions. To re-attach to a session, use the re-attach command:

[root@gigan root]#screen -r 31619.ttyp2.gigan

Just use screen with the -r flag and the session name. You are now re-attached to the screen. A nice thing about this, is you can re-attach from anywhere. If you are at work or a clients office, you can use screen to start a job and then logout. When you get back to your office or home, you can login and get back to work.

Screen Logging

As a consultant, I find it important to keep track of what I do to someone’s server. Fortunately, screen makes this easy. Using “Ctrl-A” “H”, creates a running log of the session. Screen will keep appending data to the file through multiple sessions. Using the log function is very useful for capturing what you have done, especially if you are making a lot of changes. If something goes awry, you can look back through your logs.

Linux Screen Tips

Just wanted to mention to other cool tricks you can do with screen. Screen can monitor a window for activity or lack thereof. This is great if you are downloading large files, compiling, or watching for output. If you are downloading something or compiling, you can watch for silence. To start the monitor, go to the screen you want to monitor and use “Ctrl-A” “M” to look for activity or “Ctrl-A” “_” to monitor for silence. Then open or switch to a new window. When the monitor detects activity or silence, you will get an alert at the bottom with the window number. To quickly go to that window, use “Ctrl-A” “ (thats a quote mark, ctrl-a then a “). After you do this, just type in the number of the window and enter. To stop monitoring, go to that window and undo the monitor with the same command. For example, to stop monitoring for activity you would use “Ctrl-A” “M” again.

Reference

Screen was covered recently in Linux Magazine by Adam Lazur (Jan 2003, Issue 105). Much of his information was adapted for this rackTIP. Other information was collected from the man pages.

SCP / SSH recipes

1
scp [[user@]from-host:]source-file  [[user@]to-host:][destination-file]

Description of options

from-host
Is the name or IP of the host where the source file is, this can be omitted if the from-host is the host where you are actually issuing the command
user
Is the user which have the right to access the file and directory that is supposed to be copied in the cas of the from-host and the user who has the rights to write in the to-host
source-file
Is the file or files that are going to be copied to the destination host, it can be a directory but in that case you need to specify the -r option to copy the contents of the directory
destination-file
Is the name that the copied file is going to take in the to-host, if none is given all copied files are going to maintain its names

Options

-p
Preserves the modification and access times, as well as the permissions of the source-file in the destination-file
-q
Do not display the progress bar
-r
Recursive, so it copies the contents of the source-file (directory in this case) recursively
-v
Displays debugging messages

Examples

scp *.txt user@remote.server.com:/home/user/

This will copy all files with .txt extension to the directory /home/user in the remote.server.com host

scp -r miguel@10.1.2.2:/home/miguel/ miguel@10.1.2.3:/home/miguel/

This is going to recursively copy all files from miguel’s Home directory on 10.1.2.2 host to his Home directory in 10.1.2.3 host.

——————————

Using SSH and compressed tar gzipped (compressed for faster transfer).

Code:
tar czf - </path/to/file_or_folder> --exclude LEAVE | ssh <user@host> tar xzf - -C </path/to/copy_to>

Note:
If you are familiar with the tar command then you know that if you start at say “/” and tar the path “/var/www/html” then when you un-tar you will have the full path in that tar file (/var/www/html). If you wish to avoid this, the cd to “/var/www/html” and “tar ./*” so that you do NOT have full path recursion.

—–

Examples

Copy the file “foobar.txt” from a remote host to the local host

    $ scp your_username@remotehost.edu:foobar.txt /some/local/directory

Copy the file “foobar.txt” from the local host to a remote host

    $ scp foobar.txt your_username@remotehost.edu:/some/remote/directory

Copy the directory “foo” from the local host to a remote host’s directory “bar”

    $ scp -r foo your_username@remotehost.edu:/some/remote/directory/bar

Copy the file “foobar.txt” from remote host “rh1.edu” to remote host “rh2.edu”

    $ scp your_username@rh1.edu:/some/remote/directory/foobar.txt \
    your_username@rh2.edu:/some/remote/directory/

Copying the files “foo.txt” and “bar.txt” from the local host to your home directory on the remote host

    $ scp foo.txt bar.txt your_username@remotehost.edu:~

Copy multiple files from the remote host to your current directory on the local host

    $ scp your_username@remotehost.edu:/some/remote/directory/\{a,b,c\} .
    $ scp your_username@remotehost.edu:~/\{foo.txt,bar.txt\} .

scp Performance

By default scp uses the Triple-DES cipher to encrypt the data being sent. Using the Blowfish cipher has been shown to increase speed. This can be done by using option -c blowfish in the command line.

    $ scp -c blowfish some_file your_username@remotehost.edu:~

It is often suggested that the -C option for compression should also be used to increase speed. The effect of compression, however, will only significantly increase speed if your connection is very slow. Otherwise it may just be adding extra burden to the CPU. An example of using blowfish and compression:

$ scp -c blowfish -C local_file your_username@remotehost.edu:~

The most simple case

In the most simple case, you can connect to a server that supports ssh with a syntax as short as this:

[rechosen@localhost ~]$ ssh yourserver

Note: If you do not have any ssh server nearby that you can access, you can also try this command with your own computer as a server. To do this, replace “yourserver” with “localhost”.

Of course, yourserver should be replaced by a hostname or an ip address of the server you want to connect to. As you can see in the terminal snippet, I am logged in as rechosen. If you do not specify a username (I’ll explain how to do that later in this tutorial), SSH will assume that you want to login with the username you’re currently logged in with. So, in this case, SSH will try the username rechosen.

Of course, you need to be sure that the server supports ssh connections. The ssh client tries to connect to port 22 defaultly. This means that, if you want to connect to a remote host with the default settings, you should make sure that, if applicable, port 22 is forwarded to the server you’re trying to connect to. You will find more regarding the SSH port further in this tutorial.

Now, back to the command we ran. If the server supports SSH connections and you can reach it by port 22, you should be prompted for a password (if this is the first time you try to connect to the server, ssh will first ask the question if you want to continue connecting, which can generally just be answered with a ‘yes’). If you type a password here, you won’t see asterisks appearing. Don’t panic, this is ssh’s normal behaviour. It makes connecting using ssh even more safe, because any accidental spectators won’t be able to see the length of the password. After entering the password, if the username and the password were correct, you should be running a shell on the server. If not, make sure you are connecting to a server of which you know that you should be able to login with your username and the specified password. You could try connecting to your own computer (see the note beneath the terminal quote) or read on to learn how to specify an other username.

Once you’re done trying the ssh shell, you can exit it by pressing Ctrl + D.

Specifying a username

It’s actually quite simple to specify a different username. You might even already be familiar with it. See the following example:

[rechosen@localhost ~]$ ssh yourusername@yourserver

The above will make ssh try to connect with the username “yourusername” instead of (in my case) rechosen. This syntax is also used by a lot of other protocols, so it’ll always come in handy to know it. By the way, you will still be asked for a password. For security reasons, it is not even possible to directly specify the password in the syntax. You will always be asked interactively, unless you start configuring the server in an advanced way (which is exactly why that topic is out of this tutorials scope: this tutorial documents how to use the clients, not how to configure the server).

Specifying a port

There are many reasons to move the ssh service to an other port. One of them is avoiding brute-force login attempts. Certain hackers try to get access to ssh servers by trying a lot of common usernames with common passwords (think of a user “john” with password “doe”). Although it is very unlikely that these hackers will ever get access to the system, there is an other aspect of the brute-force attacks that you’ll generally want to avoid: the system and connection load. The brute-force attacks usually are done with dozens or even thousands of tries a second, and this unnecessarily slows down the server and takes some bandwidth which could’ve been used a lot better. By changing the port to a non-default one, the scripts of the hackers will just be refused and most of the bandwidth will be saved.

As the ssh command can’t just guess the port, we will have to specify it if it’s not the default 22 one. You can do that this way:

[rechosen@localhost ~]$ ssh -p yourport yourusername@yourserver

Of course, you will have to replace “yourport” with the port number. These is an important difference between ssh and scp on this point. I’ll explain it further on.

Running a command on the remote server

Sometimes, especially in scripts, you’ll want to connect to the remote server, run a single command and then exit again. The ssh command has a nice feature for this. You can just specify the command after the options, username and hostname. Have a look at this:

[rechosen@localhost ~]$ ssh yourusername@yourserver updatedb

This will make the server update its searching database. Of course, this is a very simple command without arguments. What if you’d want to tell someone about the latest news you read on the web? You might think that the following will give him/her that message:

[rechosen@localhost ~]$ ssh yourusername@yourserver wall “Hey, I just found out something great! Have a look at www.examplenewslink.com!”

However, bash will give an error if you run this command:

bash: !”: event not found

What happened? Bash (the program behind your shell) tried to interpret the command you wanted to give ssh. This fails because there are exclamation marks in the command, which bash will interpret as special characters that should initiate a bash function. But we don’t want this, we just want bash to give the command to ssh! Well, there’s a very simple way to tell bash not to worry about the contents of the command but just pass it on to ssh already: wrapping it in single quotes. Have a look at this:

[rechosen@localhost ~]$ ssh yourusername@yourserver ‘wall “Hey, I just found out something great! Have a look at www.examplenewslink.com!”‘

The single quotes prevent bash from trying to interpret the command, so ssh receives it unmodified and can send it to the server as it should. Don’t forget that the single quotes should be around the whole command, not anywhere else.

SCP

The scp command allows you to copy files over ssh connections. This is pretty useful if you want to transport files between computers, for example to backup something. The scp command uses the ssh command and they are very much alike. However, there are some important differences.

The scp command can be used in three* ways: to copy from a (remote) server to your computer, to copy from your computer to a (remote) server, and to copy from a (remote) server to another (remote) server. In the third case, the data is transferred directly between the servers; your own computer will only tell the servers what to do. These options are very useful for a lot of things that require files to be transferred, so let’s have a look at the syntax of this command:

[rechosen@localhost ~]$ scp examplefile yourusername@yourserver:/home/yourusername/

Looks quite familiar, right? But there are differences. The command above will transfer the file “examplefile” to the directory “/home/yourusername/” at the server “yourserver”, trying to get ssh acces with the username “yourusername”. That’s quite a lot information, but scp really needs it all. Well, almost all of it. You could leave out the “yourusername@” in front of “yourserver”, but only if you want to login on the server with your current username on your own computer. Let’s have a closer look at the end of the command. There’s a colon over there, with a directory after it. Just like Linux’s normal cp command, scp will need to know both the source file(s) and the target directory (or file). For remote hosts, the file(s)/directory are given to the scp command is this way.

You can also copy a file (or multiple files) from the (remote) server to your own computer. Let’s have a look at an example of that:

[rechosen@localhost ~]$ scp yourusername@yourserver:/home/yourusername/examplefile .

Note: The dot at the end means the current local directory. This is a handy trick that can be used about everywhere in Linux. Besides a single dot, you can also type a double dot ( .. ), which is the parent directory of the current directory.

This will copy the file “/home/yourusername/examplefile” to the current directory on your own computer, provided that the username and password are correct and that the file actually exists.

You probably already guessed that the following command copies a file from a (remote) server to another (remote) server:

[rechosen@localhost ~]$ scp yourusername@yourserver:/home/yourusername/examplefile yourusername2@yourserver2:/home/yourusername2/

Please note that, to make the above command work, the servers must be able to reach each other, as the data will be transferred directly between them. If the servers somehow can’t reach each other (for example, if port 22 is not open on one of the sides) you won’t be able to copy anything. In that case, copy the files to your own computer first, then to the other host. Or make the servers able to reach each other (for example by opening the port).

Well, those are the main uses of scp. We’ll now go a bit more in-depth about the differences between ssh and scp.

*: Actually you can also use it just like the normal cp command, withhout any ssh connections in it, but that’s quite useless. It requires you to type an extra ‘s’ =).

Specifying a port with scp

The scp command acts a little different when it comes to ports. You’d expect that specifying a port should be done this way:

[rechosen@localhost ~]$ scp -p yourport yourusername@yourserver:/home/yourusername/examplefile .

However, that will not work. You will get an error message like this one:

cp: cannot stat `yourport’: No such file or directory

This is caused by the different architecture of scp. It aims to resemble cp, and cp also features the -p option. However, in cp terms it means ‘preserve’, and it causes the cp command to preserve things like ownership, permissions and creation dates. The scp command can also preserve things like that, and the -p option enables this feature. The port specification should be done with the -P option. Therefore, the following command will work:

[rechosen@localhost ~]$ scp -P yourport yourusername@yourserver:/home/yourusername/examplefile .

Also note that the -P option must be in front of the (remote) server. The ssh command will still work if you put -p yourport behind the host syntax, but scp won’t. Why? Because scp also supports copying between two servers and therefore needs to know which server the -P option applies to.

Another difference between scp and ssh

Unlike ssh, scp cannot be used to run a command on a (remote) server, as it already uses that feature of ssh to start the scp server on the host. The scp command does have an option that accepts a program (the -S option), but this program will then be used instead of ssh to establish the encrypted connection, and it will not be executed on the remote host.

Tips & Tricks with ssh and scp

Quite a handy thing about scp is that it supports asterisks. You can copy all files in a remote directory in a way like this:

[rechosen@localhost ~]$ scp yourusername@yourserver:/home/yourusername/* .

And you can also just copy a whole directory by specifying the -r (recursive) option:

[rechosen@localhost ~]$ scp -r yourusername@yourserver:/home/yourusername/ .

Both of these also work when copying to a (remote) server or copying between a (remote) server and another (remote) server.

The ssh command can come in handy if you don’t know the exact location of the file you want to copy with scp. First, ssh to the (remote) server:

[rechosen@localhost ~]$ ssh yourusername@yourserver

Then browse to the right directory with cd. This is essential Linux terminal knowledge, so I won’t explain it here. When you’re in the right directory, you can get the full path with this command:

[rechosen@localhost ~]$ pwd

Note: pwd is an abbreviation of Print Working Directory, which is a useful way to remember the command.

You can then copy this output, leave the ssh shell by pressing Ctrl + D, and then paste the full directory path in your scp command. This saves a lot of remembering and typing!

You can also limit the bandwidth scp may use when copying. This is very useful if you’re wanting to copy a huge amount of data without suffering from slow internet for a long time. Limiting bandwidth is done this way:

scp -l bandwidthlimit yourusername@yourserver:/home/yourusername/* .

The bandwidth is specified in Kbit/sec. What does this mean? Eight bits is one byte. If you want to copy no faster than 10 Kbyte/sec, set the limit to 80. If you want to copy no faster than 80 Kbyte/sec, set the limit to 640. Get it? You should set the limit to eight times the maximum Kbyte/sec you want it to be. I’d recommend to set the -l option with all scp’ing you do on a connection that other people need to use, too. A big amount of copying can virtually block a whole 10 Mbit network if you’re using hubs.

Final Words

Well, that was it! I hope you learned a lot. Of course, you can always have a quick look at this tutorial again if you forgot something. Please tell other people who might be interested about this tutorial, you’ll help this blog to grow if you do =). Thank you for reading and have a lot of fun with your new knowledge!

Search lister

This little script needs a lot of help But it will recurse down through the current directory and create a listing of files, their folders, sizes, and modification dates and times. it was written to run on Windows under Cygwin.

1
2
3
4
5
#!/bin/sh
# v1 jcz 30-dec-2009
# This script will search for files of a certain type and create a text file of the results
# TODO:
#

############################
# enable for debugging #####
############################
# set -vx

############################
#  Global script variables block
############################
# Date and other variables pretty self explanatory, S is seconds
# date format is currently YYYYMMDD_HHMMSS
dater=$(date +%Y-%m-%d %H:%M:%S)
dayer=$(date +%a)
namer=$(whoami)
hoster=$(hostname)
directory=$(pwd)
filenamer=$(date +%Y%m%d_%H%M%S).txt
# sets day of the week for incremental backups
set $(date)

############################
#  Clear the screen and introduce the user to the script
############################

clear
echo “”
echo “WELCOME TO THE FIND TO LIST SCRIPT”
echo “”

############################
#  Wait for the user to enter a new file extension and capture the value as a variable
############################
echo -n “Enter file extension to search for, without the leading dot (e.g. txt): ”
read fileext

############################
#  Wait for the user to enter a new file destination
############################
echo -n “Enter a new log file destination without ending slash (e.g., /cygdrive/c ): ”
read filedest

############################
#  Create the log file for the script named after the file extension
############################
echo “—-” >> $filedest/$filenamer
# echo “—-” > $filedest/$fileext_files_from_$directory_on_$dater.txt
echo “File created on: “$dater  >> $filedest/$filenamer
echo “Setup script was run in: “$directory >> $filedest/$filenamer
echo “By user” $namer  >> $filedest/$filenamer
echo “Searching for files ending in: ” $fileext >> $filedest/$filenamer
echo “This file was written to: ” $filedest/$filenamer >> $filedest/$filenamer
echo “***************************”  >>$filedest/$filenamer
echo “” >> $filedest/$filenamer

find . -name ‘*.’$fileext -type f -print0 | xargs -0  stat -c ‘file: %N | bytes: %s | modtime: %y’ >> $filedest/$filenamer

echo -n “Hit enter to continue ”
read none

echo “”
echo “* Now I will show you the file and be done”
echo “”
echo -n “Hit enter to list or Ctrl-c to quit ”
read none
less $filedest/$filenamer

Linux/UNIX/Cygwin find command

This is another one of those notes to myself because I look this stuff up every six months.

Basics of find. The following is a complete rip off of the content at: http://content.hccfl.edu/pollock/unix/findcmd.htm

But I wanted to keep a copy safe here. Thanks Wayne Pollock on 12/30/2009 10:27:30.

FIND

The

1
-print

action lists the names of files separated by a newline.  But it is common to pipe the output of

1
find

into

1
xargs

, which uses a space to separate file names.  This can lead to a problem if any found files contain spaces in their names, as the output doesn’t use any quoting.  In such cases, when the output of

1
find

contains a file name such as

1
foo bar

and is piped into another command, that command sees two file names, not one file name containing a space.  Even without using

1
xargs

you could have a problem if the file name contains a newline character.

In such cases you can specify the action

1
-print0

instead.  This lists the found files separated not with a newline but with a null (or NUL) character, which is not a legal character in Unix or Linux file names.  Of course the command that reads the output of

1
find

must be able to handle such a list of file names.  Many commands commonly used with

1
find

(such as

1
tar

or

1
cpio

) have special options to read in file names separated with NULs instead of spaces.

You can use shell-style wildcards in the

1
-name

search argument:

find . -name foo\*bar

This will search from the current directory down for foo*bar (that is, any filename that begins with

1
foo

and ends with

1
bar

).  Note that wildcards in the name argument must be quoted so the shell doesn’t expand them before passing them to

1
find

.  Also, unlike regular shell wildcards, these will match leading periods in filenames.  (For example

1
find -name \*.txt

.)

You can search for other criteria beside the name.  Also you can list multiple search criteria.  When you have multiple criteria any found files must match all listed criteria.  That is, there is an implied Boolean AND operator between the listed search criteria. 

1
find

also allows OR and NOT Boolean operators, as well as grouping, to combine search criteria in powerful ways (not shown here.)

Here’s an example using two search criteria:

find / -type f -mtime -7 | xargs tar -rf weekly_incremental.tar
gzip weekly_incremental.tar

will find any regular files (i.e., not directories or other special files) with the criteria

1
-type f

, and only those modified seven or fewer days ago (

1
-mtime -7

).  Note the use of

1
xargs

, a handy utility that coverts a stream of input (in this case the output of

1
find

) into command line arguments for the supplied command (in this case

1
tar

, used to create a backup archive).

Using the

1
tar

option

1
-c

is dangerous here; 

1
xargs

may invoke

1
tar

several times if there are many files found and each

1
-c

will cause

1
tar

to over-write the previous invocation.  The

1
-r

option appends files to an archive.  Other options such as those that would permit filenames containing spaces would be useful in a production quality backup script.

Another use of

1
xargs

is illustrated below.  This command will efficiently remove all files named

1
core

from your system (provided you run the command as root of course):

find / -name core | xargs /bin/rm -f
find / -name core -exec /bin/rm -f '{}' \; # same thing
find / -name core -delete                  # same if using Gnu find

(The last two forms run the

1
rm

command once per file, and are not as efficient as the first form.)

One of my favorite

1
find

criteria is to locate files modified less than 10 minutes ago.  I use this right after using some system administration tool, to learn which files got changed by that tool:

find / -mmin -10

(This search is also useful when I’ve downloaded some file but can’t locate it.)

Another common use is to locate all files owned by a given user (

1
-user <em>username</em>

).  This is useful when deleting user accounts.

You can also find files with various permissions set. 

1
-perm /<em>permissions</em>

means to find files with any of the specified permissions on,

1
-perm -<em>permissions</em>

means to find files with all of the specified permissions on, and

1
-perm <em>permissions</em>

means to find files with exactly permissionsPermissions can be specified either symbolically (preferred) or with an octal number.  The following will locate files that are writeable by others (including symlinks, which should be writeable by all):

find . -perm -o=w

(Using

1
-perm

is more complex than this example shows.  You should check both the POSIX documentation for

1
find

(which explains how the symbolic modes work) and the Gnu

1
find

man page (which describes the Gnu extensions).

When using

1
find

to locate files for backups, it often pays to use the

1
-depth

option (really a criterion that is always true), which forces the output to be depth-first—that is, files first and then the directories containing them.  This helps when the directories have restrictive permissions, and restoring the directory first could prevent the files from restoring at all (and would change the time stamp on the directory in any case).  Normally,

1
find

returns the directory first, before any of the files in that directory.  This is useful when using the

1
-prune

action to prevent

1
find

from examining any files you want to ignore:

find / -name /dev -prune | xargs tar ...

When specifying time with

1
find

options such as

1
-mmin

(minutes) or

1
-mtime

(24 hour periods, starting from now), you can specify a number

1
<em>n</em>

to mean exactly

1
<em>n</em>

,

1
<em>-n</em>

to mean less than

1
<em>n</em>

, and

1
<em>+n</em>

to mean more than

1
<em>n</em>

.

Fractional 24-hour periods are truncated!  That means that

1
find -mtime +1

says to match files modified two or more days ago.

For example:

find . -mtime 0   # find files modified between now and 1 day ago
                  # (i.e., within the past 24 hours)
find . -mtime -1  # find files modified less than 1 day ago
                  # (i.e., within the past 24 hours, as before)
find . -mtime 1   # find files modified between 24 and 48 hours ago
find . -mtime +1  # find files modified more than 48 hours ago

find . -mmin +5 -mmin -10 # find files modified between
                          # 6 and 9 minutes ago

Using the

1
-printf

action instead of the default

1
-print

is useful to control the output format better than you can with

1
ls

or

1
dir

.  You can use

1
find

with

1
-printf

to produce output that can easily be parsed by other utilities or imported into spreadsheets or databases.  See the man page for the dozens of possibilities with the

1
-printf

action.  (In fact

1
find

with

1
-printf

is more versatile than

1
ls

and is the preferred tool for forensic examiners even on Windows systems, to list file information.)  For example the following displays non-hidden (no leading dot) files in the current directory only (no subdirectories), with an custom output format:

find . -maxdepth 1 -name '[!.]*' -printf 'Name: %16f Size: %6s\n'

1
-maxdepth

is a Gnu extension.  On a modern, POSIX version of

1
find

you could use this:

find . -path './*' -prune ...

On any version of

1
find

you can use this more complex (but portable) code:

find . ! -name . -prune ...

which says to prune (don’t descend into) any directories except

1
.

.

Note that

1
-maxdepth 1

will include

1
.

unless you also specify

1
-mindepth 1

.  A portable way to include

1
.

is:

 find . \( -name . -o -prune \) ...

[This information posted by Stephane Chazelas, on 3/10/09 in newsgroup comp.unix.shell.]

As a system administrator you can use

1
find

to locate suspicious files (e.g., world writable files, files with no valid owner and/or group, SetUID files, files with unusual permissions, sizes, names, or dates).  Here’s a final more complex example (which I saved as a shell script):

find / -noleaf -wholename '/proc' -prune \
     -o -wholename '/sys' -prune \
     -o -wholename '/dev' -prune \
     -o -wholename '/windows-C-Drive' -prune \
     -o -perm -2 ! -type l  ! -type s \
     ! \( -type d -perm -1000 \) -print

This says to search the whole system, skipping the directories

1
/proc

,

1
/sys

,

1
/dev

, and

1
/windows-C-Drive

(presumably a Windows partition on a dual-booted computer).  The Gnu

1
-noleaf

option tells

1
find

not to assume all remaining mounted filesystems are Unix file systems (you might have a mounted CD for instance).  The

1
-o

is the Boolean OR operator, and

1
!

is the Boolean NOT operator (applies to the following criteria).

So these criteria say to locate files that are world writable (

1
-perm -2

, same as

1
-o=w

) and NOT symlinks (

1
! -type l

) and NOT sockets (

1
! -type s

) and NOT directories with the sticky (or text) bit set (

1
! \( -type d -perm -1000 \)<!--  -->

).  (Symlinks, sockets and directories with the sticky bit set are often world-writable and generally not suspicious.)

A common request is a way to find all the hard links to some file.  Using

1
ls -li <em>file</em>

will tell you how many hard links the file has, and the inode number.  You can locate all pathnames to this file with:

  find mount-point -xdev -inum inode-number

Since hard links are restricted to a single filesystem, you need to search that whole filesystem so you start the search at the filesystem’s mount point.  (This is likely to be either

1
/home

or

1
/

for files in your home directory.)  The

1
-xdev

options tells

1
find

to not search any other filesystems.

(While most Unix and all Linux systems have a

1
find

command that supports the

1
-inum

criterion, this isn’t POSIX standard.  Older Unix systems provided the

1
ncheck

utility instead that could be used for this.)

Using

1
-exec

Efficiently:

The

1
-exec

option to

1
find

is great, but since it runs the command listed for every found file it isn’t very efficient.  On a large system this makes a difference!  One solution is to combine

1
find

with

1
xargs

as discussed above:

  find whatever... | xargs command

However this approach has two limitations.  Firstly not all commands accept the list of files at the end of the command.  A good example is

1
cp

:

find . -name \*.txt | xargs cp /tmp  # This won't work!

(Note the Gnu version of

1
cp

has a non-POSIX option

1
-t

for this, and

1
xargs

has options to handle this too.)

Secondly filenames may contain spaces or newlines, which would confuse the command used with

1
xargs

.  (Again Gnu tools have options for that,

1
find ... -print0 <!--  -->|xargs -0 ...

.)

There are POSIX (but non-obvious) solutions to both problems.  An alternate form of

1
-exec

ends with a plus-sign, not a semi-colon.  This form collects the filenames into groups or sets, and runs the command once per set.  (This is exactly what

1
xargs

does, to prevent argument lists from becoming too long for the system to handle.)  In this form the

1
{}

argument expands to the set of filenames.  For example:

find / -name core -exec /bin/rm -f '{}' +

This form of

1
-exec

can be combined with a shell feature to solve the other problem (names with spaces).  The POSIX shell allows us to use:

sh -c 'command-line' [ command-name [ args... ] ]

(We don’t usually care about the command-name, so X, dummy, or inline cmd is often used.)  Here’s an example of efficiently copying found files to

1
/tmp

, in a POSIX-compliant way (Posted on comp.unix.shell netnews newsgroup on Oct. 28 2007 by Stephane CHAZELAS):

find . -name '*.txt' -type f \
  -exec sh -c 'exec cp -f "$@" /tmp' find-copy {} +

Common Gotcha:

If the given expression to

1
find

does not contain any of the action primaries

1
-exec

,

1
-ok

, or

1
-print

, the given expression is effectively replaced by:

find \( expression \) -print

The implied parenthesis can cause unexpected results.  For example, consider these two similar commands:

$ find -name tmp -prune -o -name \*.txt
./bin/data/secret.txt
./tmp
./missingEOL.txt
./public_html/graphics/README.txt
./datafile2.txt
./datafile.txt
$ find -name tmp -prune -o -name \*.txt -print
./bin/data/secret.txt
./missingEOL.txt
./public_html/graphics/README.txt
./datafile2.txt
./datafile.txt

The lack of an action in the first command means it is equivalent to:

find . \( -name tmp -prune -o -name \*.txt \) -print

This causes

1
tmp

to be included in the output.  However for the second

1
find

command the normal rules of Boolean operator precedence apply, so the pruned directory does not appear in the output.

The

1
find

command can be amazingly useful.  See the man page to learn all the criteria and actions you can use.

See Also Stat

$ stat –help
Usage: stat [OPTION] FILE…
Display file or file system status.

-L, –dereference     follow links
-f, –file-system     display file system status instead of file status
-c  –format=FORMAT   use the specified FORMAT instead of the default;
output a newline after each use of FORMAT
–printf=FORMAT   like –format, but interpret backslash escapes,
and do not output a mandatory trailing newline.
If you want a newline, include \n in FORMAT.
-t, –terse           print the information in terse form
–append-exe      append .exe if cygwin magic was needed
–help     display this help and exit
–version  output version information and exit

The valid format sequences for files (without –file-system):

%a   Access rights in octal
%A   Access rights in human readable form
%b   Number of blocks allocated (see %B)
%B   The size in bytes of each block reported by %b
%C   SELinux security context string
%d   Device number in decimal
%D   Device number in hex
%f   Raw mode in hex
%F   File type
%g   Group ID of owner
%G   Group name of owner
%h   Number of hard links
%i   Inode number
%n   File name
%N   Quoted file name with dereference if symbolic link
%o   I/O block size
%s   Total size, in bytes
%t   Major device type in hex
%T   Minor device type in hex
%u   User ID of owner
%U   User name of owner
%x   Time of last access
%X   Time of last access as seconds since Epoch
%y   Time of last modification
%Y   Time of last modification as seconds since Epoch
%z   Time of last change
%Z   Time of last change as seconds since Epoch

Valid format sequences for file systems:

%a   Free blocks available to non-superuser
%b   Total data blocks in file system
%c   Total file nodes in file system
%d   Free file nodes in file system
%f   Free blocks in file system
%C   SELinux security context string
%i   File System ID in hex
%l   Maximum length of filenames
%n   File name
%s   Block size (for faster transfers)
%S   Fundamental block size (for block counts)
%t   Type in hex
%T   Type in human readable form

This might be handy with xargs from find. Here’s an example from cygwin that outputs a formatted display of filename, size in bytes, and date time when the file was last modified.

$ stat -c “file: %N | bytes: %s | modtime: %y” *.ini
file: `XrxWm.ini’ | bytes: 1064 | modtime: 2009-09-14 12:15:19.531250000 -0400
file: `ntuser.ini’ | bytes: 178 | modtime: 2009-12-29 09:19:04.843750000 -0500

This little command works nicely o Windows (to esacpe the spaces in file names).

$ find . -name ‘*.enl’ -type f -print0 | xargs -0  stat -c “file: %N | bytes: %s | modtime: %y” >> find-output.txt

To produce

file: `./Sample library.enl’ | bytes: 13918 | modtime: 2009-12-18 15:02:41.671875000 -0500


					

How to set a static IP in Ubuntu from the shell

Edit

1
/etc/network/interfaces

and adjust it to your needs (in this example setup I will use the IP address 192.168.0.100):

1
2
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
1
2
3
# The loopback network interface
auto lo
iface lo inet loopback
1
2
3
4
5
# This is a list of hotpluggable network interfaces.
# They will be activated automatically by the hotplug subsystem.
mapping hotplug
script grep
map eth0
1
2
3
4
5
6
7
8
# The primary network interface
auto eth0
iface eth0 inet static
address 192.168.0.100
netmask 255.255.255.0
network 192.168.0.0
broadcast 192.168.0.255
gateway 192.168.0.1

Then do

1
sudo /etc/init.d/networking restart

to restart the network.

Remastersys Notes

My latest project is to turn my favorite Linux desktop configurations into stand alone distributions that I can run as LiveCDs or install anywhere.

Here are some links so that I don’t forget.

http://www.ubuntugeek.com/creating-custom-ubuntu-live-cd-with-remastersys.html

The all powerful find command

find <starting point> <search criteria> <action>

The starting point is the name of the directory where find should start
looking for files. The find command examines all files in this
directory (and any subdirectories) to see if they meet the specified
search criteria. If any do, find performs the specified action on each
found file. Here are some of the most useful search criteria options:

-name pattern Find files with names that match the pattern.
-size [+|-] n Find files larger or smaller than a certain size.
-atime [+|-] n Find files accessed before or after a certain date.
-mtime [+|-] n Find files modified before or after a certain date.
-type filetype Find only regular files or only directories.

And here are the actions that can be applied to found files:

-print Print just the names of matching files.
-ls Print the names, dates, sizes, and so on of matching files.
-exec command Execute a command with the file name as input.
-ok command Same as -exec, but asks for confirmation first.

That all might look a bit confusing, so here are some examples to bring
things down to earth. To find files (starting in the current directory)
with names ending with .data and to print their names, try this:

find . -name ‘*.data’ -print
company.data
donor.data
grades.data
sorted.data
words.data

To find files larger than 40K and print the file names and details (use
a minus sign instead of a plus sign to find files smaller than a
certain size), issue this command:

find . -size +40k -ls

To find all files modified within the last 5 days:

find / -mtime -5 -print

The – in front of the 5 modifies the meaning of the time as “less than five days.” The command

find / -mtime +5 -print

To find all files with zero length and ask if they should be deleted:

find / -size 0 -ok rm {} ;

Another Linux Web MySQL Backup Script

I found this on on the nixcraft craft. Looks pretty good to me. Similar
in functionality to my other script posted here. I’m going to poach
some concepts from here to make a script that will auto-optimize all
tables in all databases on the mysql server.

#!/bin/sh
##################
## jcz 17-feb-2007
## copied from http://www.cyberciti.biz/tips/
## how-to-backup-mysql-databases-web-server-
## files-to-a-ftp-server-automatically.html
##############################################
## System + MySQL backup script
## Full backup day – Sun (rest of the day do incremental backup)
## Copyright (c) 2005-2006 nixCraft
## This script is licensed under GNU GPL version 2.0 or above
## Automatically generated by http://bash.cyberciti.biz/backup/wizard-ftp-script.php
## Make full backup every Sunday night
## i.e. backup everything every Sunday
## Next backup only those files that
## have been modified since the full
## backup (incremental backup)
##################################################
## * This is a seven-day backup cycle.
## * It will store data as follows:
## * /home/nixcraft/full/mm-dd-yy/files – Full backup
## * /home/nixcraft/incremental/mm-dd-yy/files – Incremental backup
## * 1. First script will collect all data from both
## * MySQL database server and from file system to
## * temporary directory called /backup using tar command
## * 2. Next, script will login to ftp server and
## * create a directory structure as discussed above
## * 3. Script will dump all files from /backup to ftp server
## * 4. Script will remove temporary backup from /backup
## * 5. Script will send you an email notification
## * if ftp backups failed due to any reason.
##
## * You must have following command installed:
##
## * ncftp ftp client
## * mysqldump command
## * GNU tar command
###########################################
# ———————————————————————
### System Setup ###
DIRS=”/home /etc /var/www”
BACKUP=/tmp/backup.$$
NOW=$(date +”%d-%m-%Y”)
INCFILE=”/root/tar-inc-backup.dat”
DAY=$(date +”%a”)
FULLBACKUP=”Sun”
### MySQL Setup ###
MUSER=”admin”
MPASS=”mysqladminpassword”
MHOST=”localhost”
MYSQL=”$(which mysql)”
MYSQLDUMP=”$(which mysqldump)”
GZIP=”$(which gzip)”
### FTP server Setup ###
FTPD=”/home/vivek/incremental”
FTPU=”vivek”
FTPP=”ftppassword”
FTPS=”208.111.11.2?
NCFTP=”$(which ncftpput)”
### Other stuff ###
EMAILID=”admin@theos.in”
### Start Backup for file system ###
[ ! -d $BACKUP ] && mkdir -p $BACKUP || :
### See if we want to make a full backup ###
if [ “$DAY” == “$FULLBACKUP” ]; then
FTPD=”/home/vivek/full”
FILE=”fs-full-$NOW.tar.gz”
tar -zcvf $BACKUP/$FILE $DIRS
else
i=$(date +”%Hh%Mm%Ss”)
FILE=”fs-i-$NOW-$i.tar.gz”
tar -g $INCFILE -zcvf $BACKUP/$FILE $DIRS
fi
### Start MySQL Backup ###
# Get all databases name
DBS=”$($MYSQL -u $MUSER -h $MHOST -p$MPASS -Bse ’show databases’)”
for db in $DBS
do
FILE=$BACKUP/mysql-$db.$NOW-$(date +”%T”).gz
$MYSQLDUMP -u $MUSER -h $MHOST -p$MPASS $db | $GZIP -9 > $FILE
done
### Dump backup using FTP ###
#Start FTP backup using ncftp
ncftp -u”$FTPU” -p”$FTPP” $FTPS<
mkdir $FTPD
mkdir $FTPD/$NOW
cd $FTPD/$NOW
lcd $BACKUP
mput *
quit
EOF
### Find out if ftp backup failed or not ###
if [ "$?" == "0" ]; then
rm -f $BACKUP/*
else
T=/tmp/backup.fail
echo “Date: $(date)”>$T
echo “Hostname: $(hostname)” >>$T
echo “Backup failed” >>$T
mail -s “BACKUP FAILED” “$EMAILID” <$T
rm -f $T
fi