It calls the isatty() libc function on its stdout file descriptor to determine whether the output goes to a terminal or not.
Internally, isatty() attempts to use one of the ioctl() calls that are specific to tty devices – most likely ioctl(TCGETS) (which retrieves the generic tty settings that the stty command shows); if it succeeds, then the file is a tty device.
$ python
>>> sys.stdout.isatty()
True
This affects both whether ls will columnate its output by default, and whether it will use colors by default, and some other things such as whether file names will be quoted.
If stdout is indeed a terminal, then ls uses another tty-specific ioctl(TIOCGWINSZ) to retrieve its dimensions (which on modern systems have been stored there by the terminal emulator) to find out how many columns it can fit. The stty size command also gets those; try running it under strace.
Full-screen programs additionally react to the SIGWINCH signal which the kernel sends every time the terminal emulator updates the dimensions of the tty, as an indication that they need to redraw everything in the new size.
It calls the isatty() libc function on its stdout file descriptor to determine whether the output goes to a terminal or not.
Internally, isatty() attempts to use one of the ioctl() calls that are specific to tty devices – most likely ioctl(TCGETS) (which retrieves the generic tty settings that the stty command shows); if it succeeds, then the file is a tty device.
$ python
>>> sys.stdout.isatty()
True
This affects both whether ls will columnate its output by default, and whether it will use colors by default, and some other things such as whether file names will be quoted.
If stdout is indeed a terminal, then ls uses another tty-specific ioctl(TIOCGWINSZ) to retrieve its dimensions (which on modern systems have been stored there by the terminal emulator) to find out how many columns it can fit. The stty size command also gets those; try running it under strace.
Full-screen programs additionally react to the SIGWINCH signal which the kernel sends every time the terminal emulator updates the dimensions of the tty, as an indication that they need to redraw everything in the new size.
For a less technical explanation, observe what happens when you try these two commands:
$ ls
update.sh web.config MyApp.runtimeconfig.json
$ ls | cat
update.sh
web.config
MyApp.runtimeconfig.json
Piping through cat "does nothing", except that ls "notices" that it's output is being piped somewhere. So it changes its behavior accordingly.
Once you understand what ls is outputting, it's straightforward what happens when it passes through head -n1.
It's because * doesn't match files starting with a . by default. Consider the following directory:
$ ls -la
total 8404
drwxrwxrwx 2 terdon terdon 8105984 Dec 31 13:14 .
drwxr-xr-x 153 terdon terdon 491520 Dec 30 22:32 ..
-rw-r--r-- 1 terdon terdon 0 Dec 31 13:14 .dotfile
-rw-r--r-- 1 terdon terdon 0 Dec 31 13:14 file1
-rw-r--r-- 1 terdon terdon 0 Dec 31 13:14 file2
-rw-r--r-- 1 terdon terdon 0 Dec 31 13:14 file3.
Let's see what each of the globs you used expands to:
$ echo .*
. .. .dotfile
$ echo *.
file3.
$ echo *
file1 file2 file3.
As you can see, the * does not include files or directories starting with . so both ./ and ../ are ignored. The same thing happens with your ls example. In bash, you can change this with the dotglob parameter, which will cause * to expand to dotfiles as well (but not to . or .., those are still ignored):
$ shopt -s dotglob
$ echo *
.dotfile
Other shells behave differently. For example zsh also ignores the . and .. when using .*:
% echo .*
.dotfile
The rule for filename expansion have a special case for . as the first character in a filename: it must be explicitly matched (i.e. the pattern must contain a starting ., or . after a /). Otherwise these files are not candidates.
This is why your first version does pick up filenames that start with ., but the second doesn't. * doesn't match . as the first character of a filename.
POSIX Shell Command Language describes it as:
If a filename begins with a period ( '.' ), the period shall be explicitly matched by using a period as the first character of the pattern or immediately following a slash character. The leading period shall not be matched by:
- The asterisk or question-mark special characters
- A bracket expression containing a non-matching list, such as "[!a]", a range expression, such as "[%-0]", or a character class expression, such as "[[:punct:]]"
It is unspecified whether an explicit period in a bracket expression matching list, such as "[.abc]", can match a leading period in a filename.
Your shell might have options to change this behavior. Bash has this for instance (Filename expansion):
When a pattern is used for filename expansion, the character ‘.’ at the start of a filename or immediately following a slash must be matched explicitly, unless the shell option dotglob is set. When matching a file name, the slash character must always be matched explicitly. In other cases, the ‘.’ character is not treated specially.
Note that these are not regular expressions. .* as a regex would match anything at all (including nothing). *. would be ill-formed.
You've changed your script to use Model=Report and ${Model} and you've said you have typeset -u Model in your script. The -u option to the typeset command (instead of declare — they're synonyms) means "convert the strings assigned to all upper-case".
-uWhen the variable is assigned a value, all lower-case characters are converted to upper-case. The lower-case attribute is disabled.
That explains the upper-case REPORT in the variable expansion. You can demonstrate by writing:
Model=Report
echo "Model=[${Model}]"
It would echo Model=[REPORT] because of the typeset -u Model.
- Don't use the
-uoption if you don't want it.
You should probably fix your glob expression too:
file=
{Model}_execution_*${DATE}*.pdf)
Using $(…) instead of backticks is generally a good idea.
And, as a general point, learn how to Debug a Bash Script and always provide an MCVE (How to create a Minimal, Complete, and Verifiable Example?) so that we can see what your problem is more easily.
Some things to look at:
typeis usually a reserved word, though it won't break your script, I suggest you to change that variable name to something else.- You are missing an
$before{DATE}, and you have an extra_after it. If the date is the last part of the name, then there's no point in having an*at the end either. Thefiledefinition should be:
file=`ls ${type}_execution_*${DATE}.pdf`
Try debugging your code by parts: instead of doing an ls, do an echo of each variable, see what comes out, and trace the problem back to its origin.
As @DevSolar pointed out you may have problems parsing the output of ls.
It's the number of (by default, 1K) blocks. From the description of -ls in the texinfo documentation (info find -n 'Print File Information'):
-- Action: -ls
True; list the current file in 'ls -dils' format on the standard
output. The output looks like this:
204744 17 -rw-r--r-- 1 djm staff 17337 Nov 2 1992 ./lwall-quotes
The fields are:
1. The inode number of the file. *Note Hard Links::, for how to
find files based on their inode number.
2. the number of blocks in the file. The block counts are of 1K
blocks, unless the environment variable 'POSIXLY_CORRECT' is
set, in which case 512-byte blocks are used. *Note Size::,
for how to find files based on their size.
3. The file's type and file mode bits. The type is shown as a
dash for a regular file; for other file types, a letter like
for '-type' is used (*note Type::). The file mode bits are
read, write, and execute/search for the file's owner, its
group, and other users, respectively; a dash means the
permission is not granted. *Note File Permissions::, for more
details about file permissions. *Note Mode Bits::, for how to
find files based on their file mode bits.
...
It seems to me that the second column in the output of
find -ls
is the drive space occupied in kibibytes, corresponding [at least for files] to the output of du (default matching du -k). For directories it is the drive space occupied for the directory structure itself (not including the data in the files in the directory, but the addresses to the files, so the number increases, when there are many files in the directory).
Please notice that in current Ubuntu systems, the minimum drive space allocated to a file is 4 kibibytes.
The option '-l' tells the command to use a long list format. It gives back several columns wich correspond to:
- Permissions
- Number of hardlinks
- File owner
- File group
- File size
- Modification time
- Filename
The first letter in the permissions column show the file's type. A 'd' means a directory and a '-' means a normal file (there are other characters, but those are the basic ones). The next nine characters are divided into 3 groups, each one a permission. Each letter in a group correspond to the read, write and execute permission, and each group correspond to the owner of the file, the group of the file and then for everyone else.
- [ File type ][ Owner permissions ][ Group permissions ][ Everyone permissions ]
The characters can be one of four options:
- r = read permission
- w = write permission
- x = execute permission
-= no permission
Finally, the "+" at the end means some extended permissions.
If you type the command
$ man ls
You’ll get the documentation for ls, which says in part:
The Long Format
If the-loption is given, the following information is displayed for each file: file mode, number of links, owner name, group name, number of bytes in the file, abbreviated month, day-of-month file was last modified, hour file last modified, minute file last modified, and the pathname. In addition, for each directory whose contents are displayed, the total number of 512-byte blocks used by the files in the directory is displayed on a line by itself, immediately before the information for the files in the directory. If the file or directory has extended attributes, the permissions field printed by the-loption is followed by a '@' character. Otherwise, if the file or directory has extended security information (such as an access control list), the permissions field printed by the-loption is followed by a '+' character.
…
The man command is short for “manual”, and the articles it shows are called “man pages”; try running man manpages to learn even more about them.