while read link; do target=$(readlink "$link") [ -d "$target" ] && continue it's not possible to target a directory with a hard link # echo "$link --> $target" ls -l "$link" echo '===============================' mv "$link" "$link"_DISABLED ln "$target" "$link" done < <(find -type l)
with the arithmetic expansion operator $(()) |
with let | with expr | |
---|---|---|---|
declare a variable | myVariable=value no space allowed before or after the = |
||
do basic operations :+ , - , * or / |
a=3; echo $((a + 2)) $((a - 2)) $((a * 2)) $((a / 2))
5 1 6 1
|
a=3; let b=a+2; let c=a-2; let d=a*2; let e=a/2; echo $b $c $d $e
5 1 6 1
|
a=3; expr $a + 2; expr $a - 2; expr $a \* 2; expr $a / 2
5 1 6 1 |
|
|||
increment / decrement |
a=3; echo $((a++)); echo $((++a)); echo $a
3 |
a=3; let a++; echo $a; let ++a; echo $a
4 5 |
not possible |
modulo : % |
0 1 2 0 1 2 0 1 2 0 0 10 20 30 40 50 60 70 80 90 100 |
$[]
operator ?$(())
$[]
operator mentioned here.$(())
is POSIX standard$[]
is Bash-specific + obsoleteThe old format $[expression] is deprecated and will be removed in upcoming versions of bash.
212B
\U
has turned uppercase.\u
and \U
? (source)\u
introduces a value made of 4 hex digits\U
introduces a value made of (up to) 8 hex digits\b
actually moves the cursor 1 character left but prints nothing. To simulate a backspace
, you'll have to :
space
sleepDuration='0.1'; echo -en '\033[1;31mO\033[0;33m o===B\033[0m'; sleep 0.8 echo -en '\b\b\b\b\b\b\b\033[1;31mO\033[0;33mo===B\033[0m '; sleep 0.8 while true; do echo -en '\b\b\b\b\b\b\b\b\033[1;31mO\033[0;33m===B\033[0m '; sleep $(echo $sleepDuration*2 | bc) echo -en '\b\b\b\b\b\b\b\033[1;31mO\033[0;33m==B\033[0m '; sleep $sleepDuration echo -en '\b\b\b\b\b\033[0;33mB\033[0m '; sleep $sleepDuration echo -en '\b\b\b\b\b\b\033[0;33mB\033[0m '; sleep $sleepDuration echo -en '\b\b\b\b\b\b\b\033[1;31mO\033[0;33m=B\033[0m '; sleep $sleepDuration done
This construct can work as commandIfSuccess
/ commandIfFailure
only because command2 never fails (this is where the magic comes from). Check it (source) :
From the example above, you must remember that, if command2 fails, both command2 and command3 will be executed :
hello
hello world
All of this is because lists of commands using && and || are executed with left associativity (What is left associativity ?)
command1 && command2 || command3
and command1 || command2 && command3
have totally different effects :
()
is a success, and command3 is evaluated()
is a failure, so command3 is not evaluated 1st half of the "ternary operator"()
is a failure, so command3 is evaluated 2nd half of the "ternary operator"()
is a success, so command3 is evaluated()
is a success, so command3 is evaluated()
is a failure, so command3 is not evaluatedcommand1 && command2 || command3
...if command1; then command2 else command3 fi
Command | Usage | Command Line | Output | Notes |
---|---|---|---|---|
cksum | compute checksum and file size | cksum file1 file2 |
checksum sizeInBytes file1 checksum sizeInBytes file2 |
see also : |
cmp | compare files byte by byte | cmp file1 file2 |
|
works both with ASCII and binary files |
comm | compare sorted files line by line | |||
diff | compare files line by line | diff file1 file2 |
|
works both with ASCII and binary files |
vimdiff | compare files side by side | vimdiff file1 file2 |
TMOUT
readonly, that /usr/bin/gdb (from gdb) is not available anyway (maybe building a static gdb binary could do the trick)# Disable the stupid auto-logout unset TMOUT >/dev/null 2>&1 if [ $? -ne 0 ]; then gdb <<EOF >/dev/null 2>&1 attach $$ call unbind_variable("TMOUT") detach quit EOF fi
Safe values :
Everything is a file., remember ?), directories are "files listing files" (including sub-directories). They do so by matching an inode number (i.e. where the data is found on the filesystem) to a label (the file name). And since this is just a list of matching inode / label, nothing forbids several labels to share the same inode. Which is exactly what hard links do. (sources : 1, 2)
File: someFile Size: 3369 Blocks: 8 IO Block: 4096 regular file Device: 801h/2049d Inode: 281693 Links: 4 Access: (0600/-rw-------) Uid: ( 1000/ stuart) Gid: ( 1000/ stuart) Access: 2019-09-30 10:38:49.287324976 +0200 Modify: 2019-09-19 11:37:59.255500842 +0200 Change: 2019-09-30 10:39:49.913512315 +0200 Birth: -
File: someFile Size: 3369 Blocks: 8 IO Block: 4096 regular file Device: 2dh/45d Inode: 399 Links: 1 Access: (0600/-rw-------) Uid: ( 1000/ stuart) Gid: ( 1000/ stuart) Access: 2019-09-30 10:38:49.000000000 +0200 Modify: 2019-09-19 11:37:59.000000000 +0200 Change: 2019-09-19 11:37:59.000000000 +0200 Birth: -
135340 -rw-r--r-- 2 kevin users 9042 Sep 19 15:05 suspectFile 135340 -rw-r--r-- 2 kevin users 9042 Sep 19 15:05 target
135340 suspectFile
/path/to/suspectFile /different/path/to/someFile
/path/to/suspectFile /different/path/to/someFile
File: suspectFile Size: 9042 Blocks: 24 IO Block: 4096 regular file Device: fe04h/65028d Inode: 135340 Links: 2 more than 1 link : this is a hard link Access: (0644/-rw-r--r--) Uid: ( 1000/ kevin) Gid: ( 1000/ users) Access: 2018-09-19 15:05:26.103989305 +0200 Modify: 2018-09-19 15:05:26.103989305 +0200 Change: 2018-09-20 14:11:38.766124455 +0200 Birth: -
^[
here is an escape sequence and stands for \e
. So the final code for F9 is \e[20~.# CTRL-F11 : display "/etc/apache2/sites-enabled/" "\e[23;5~":"/etc/apache2/sites-enabled/" # CTRL-F12 : display "/var/www/" "\e[24;5~":"/var/www/"
If the key bindings must work through Putty, the configuration becomes :
# F11 : display "/etc/apache2/sites-enabled/" "\e[23~":"/etc/apache2/sites-enabled/" # F12 : display "/var/www/" "\e[24~":"/var/www/"
~/.inputrc is a readline config file, not a Bash one, so it can not be source'd. Instead, it may be loaded at Bash startup. (source, details)
I/O name | file descriptor |
---|---|
STDIN | 0 |
STDOUT | 1 |
STDERR | 2 |
<
and >
:
<
: redirecting the input, i.e. reading from somewhere>
: redirecting the output, i.e. writing to somewhere<>
: redirecting both for reading and writingall subsequent commands(affecting the shell itself, actually) with exec.
<<
: aka here documents>>
: like >
but appends to the destination file instead of overwriting it>>>
: aka here strings0
/ stdin when reading : command < myFile
means command 0< myFile
1
/ stdout when writing : command > myFile
means command 1> myFile
-
, n is closed-
, n is closedls --nonExistentOption > myFile 2>&1 (nothing) cat myFile ls: unrecognized option '--nonExistentOption' the error message has been written to myFile Try 'ls --help' for more information. ls --nonExistentOption 2>&1 > myFile ls: unrecognized option '--nonExistentOption' the error message has been written to stdout Try 'ls --help' for more information. cat myFile (nothing)
where STDOUT is, i.e. follow the same redirection
There is no "ninja hack" to this : if some output is still displayed despite the redirection, make sure you're actually redirecting the output of the right command.
a=42 a=42$a
is "passed" inside of the()
b=12 a=0$a
can be overwritten inside of the()
b=12 a=42 the changed value of$a
doesn't exist outside of the()
b=$b
doesn't exist outside of()
;
(or newline) is required after listOfCommands.
a=42 a=42 this is the same "$a
" since it's the same shell context b=12 a=0 we can do whatever we like b=12 a=0 being in the same shell context means variables stay altered outside of the{}
b=12$b
now exists outside of{}
{
and }
are reserved words, so they must be separated from the list by blanks.-
is interpreted as a command option prefix.--
(sources : 1, 2) :testDir='/tmp'; touch "$testDir/-foo"; inodeNumber=$(ls -i "$testDir/"*foo | cut -d' ' -f1); find "$testDir" -inum "$inodeNumber"
This lists much more than only /tmp/-foo .Solution at the end of this article
cd 201611but to go further you have to hit TAB + TAB again to see the available options
20161115_workOnSomeStuff/ 20161121-25_support/ 20161122_otherProject/so now you have to figure out which character to type next : 2 + TAB + TAB again for available options
20161121-25_support/ 20161122_otherProject/Type the next character : 1 + TAB
cd 20161121-25_support/
All the magic here is in the shell expansion of the wildcard *
+ rt to match any directory which name ends in rt.
Writing $i_old
for the target (with or without quotes) causes an error because the underscore character _
is allowed in variable names, and in such case, Bash will search a variable named i_old
, which doesn't exist. (More on Bash variables : 1, 2)
for i in *oldExtension; do mv "$i" $(basename "$i" .oldExtension).newExtension; done
for file in *; do mv "$file" "${file/before/after}"; done
drwxr-xr-x 5 bob users 4096 jun. 25 21:19 normalDirectory_1 drwxr-xr-x 6 bob users 4096 nov. 18 07:46 normalDirectory_2 drwxr-xr-x 4 bob users 4096 dec. 1 18:48 normalDirectory_3 drwxr-xr-x 3 bob users 4096 nov. 28 10:00 ?weirdDirectory what's wrong with this one ?
This ?weirdDirectory contains a non-printable character in its name represented by a ?
by ls. BTW, ls can do more for us and report the octal code of this special character with its -b flag (but this is of no help here).
This is even worse when the special character is the 1st one, because we can't even be saved by Bash completion.
All of this is inspired by a true story, while trying to browse directories on a remote server (where locales were possibly quite f***ed up) via PuTTY + screen (possibly poorly configured also). That server had directories — wherever they came from — with letters such as éèà
... and since I couldn't type them in my terminal (even copy-pasting), I could not enter those directories.
<spoiler_alert>We'll have to create such a directory for the demonstration, which lets the cat out of the bag on the solution</spoiler_alert>
Let's create a directory named €uro, then enter it (as said earlier, this is piece of cake when sitting in front of a properly configured host, and everything below is meaningless) :
€
symbol here : 240
�uro
drwxr-xr-x 2 bob users 4,0K déc. 3 17:17 ?uro/
Actually, cd $(ls -d ?uro) would have done the job perfectly but might be confusing : ls -l "displays" the directory name with a ?
because the terminal itself is not able to display it, whereas the ?
in the cd $(ls ) command is a wildcard representing a single character.
{}
and ()
Many articles answer this question suggesting to parse the output of ifconfig (ip a should be preferred, actually) with the usual grep, cut, awk et al.
This is very nice, but already available with :[SPACE]