home / infca / linux / lshell (navigation links) Ned - no matter what you think, i do love you

Hints | She Bang | Parameters | Timestamp | built-in coommands, shell functions, my alias, bash user functions
heredoc | Perl (ext) | cron (ext) | rare string ops | do ftp, tcpip
if then else | while, *** complete ***
cnt ko | bash details | debug a shell | cnt ok | quotes | own global tool
jq | cut & sed & awk | line endings | REST API client
Dubtes | Links | End | mapa

Linux shell code

go 2 top

she bang | parameters | timestamp | debug a shell |

shells

A Unix shell is a command-line interpreter or shell that provides a command line user interface for Unix-like operating systems.

The shell is both an interactive command language and a scripting language, and is used by the operating system to control the execution of the system using shell scripts.

Shell scripting can be defined as a group of commands executed in sequence.

Per exemple, per fer un grep per un string_buscat en tots els fitxers *.c del directori actual i subdirectoris, podem fer :

exemple minim

#!/bin/bash # Autor : jo myLog="/home/mate/logs/mylog.log" # log file echo "+++ [`date -R`] +++ ("$0") +++" >> $myLog # ident by prog name exit 0

Shell bits

Style, tips

shell variables concatenation

Do it joining their names :

fqDest="/media/sebas/"${myParam}
shell variables hints

We can access the value of the variable using the dollar sign ($):

$ A=2 $ echo $A 2

We can additionally use curly brackets to separate the variable’s name from the rest of the expression:

$ echo ${A}string 2string
To quote or not to quote

Always quote variable expansions even when you know the value won't contain any IFS characters
This makes the contents of the variable an atomic unit.
If the variable value contains blanks (well, characters in the $IFS special variable, blanks by default) or globbing characters and you don't quote it, then each word is considered for filename generation (globbing) whose expansion makes as many arguments to whatever you're doing.

stackExchange

EX_VARIABLE="24/22/2021" SQL_MSG=`sqlplus -s <user>/<pwd>@<db> <<-EOF whenever SQLERROR EXIT SQL.SQLCODE ROLLBACK; whenever OSERROR EXIT SQL.SQLCODE ROLLBACK; select to_date('${EX_VARIABLE}','dd/mm/yyyy') from dual; EOF` if [ $? -eq 0 ]; then echo "OK"; else echo "${SQL_MSG}" # very important quotes here fi
Using curling parenthesis in var names

both $VAR and ${VAR} are used to access the value of a variable
And in many cases, they work the same. But ${VAR} is more versatile and safer in certain situations.

Use ${VAR} when:

😎 in doubt — just go with ${VAR} 😎


Amunt! Top Amunt!
shell init file sequence(s)

bash files
reload profile without "logoff"

Do ". ~/.profile" (mind the initial dot followed by a space)

pi@R4:~ $ . ~/.profile +++ .bash_aliases - v1.1a 20210518 --- .bash_aliases - v1.1a 20210518 pi@R4:~ $
what is a login or non-login shell?

When you login (type username and password) via console, either sitting at the machine, or remotely via ssh, .bash_profile is executed to configure your shell before the initial command prompt.
But, if you’ve already logged into your machine and open a new terminal window (xterm) inside Gnome or KDE, then .bashrc is executed before the window command prompt. .bashrc is also run when you start a new bash instance by typing /bin/bash in a terminal


Amunt! Top Amunt!
PATH

PATH is system-wide set at /etc/profile
User can modify it :

# set PATH so it includes user's private bin directories PATH="$HOME/bin:$HOME/.local/bin:$PATH"

On Ubuntu we place this line in "~/.profile" or "~/.bashrc" (better)


Amunt! Top Amunt!
She-Bang : #!

The first line of a shell file tells the computer how to interpret this script.

Un classic de BASH :

#!/bin/bash myLog="/home/mate/logs/mylog.log" echo "+++ [`date -R`] +++ ("$0") +++" >> $myLog exit 0

Un exemple de Perl :

#!/usr/bin/perl print "Look at all the camels!\n";

Un exemple de Bourne Shell :

#!/bin/sh echo "El Path es" $PATH echo "El Path es" ${PATH} echo "[`date -R`] - Different Hash, New Passwd File"; # Print the IP address _IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi

Un exemple de Rexx :

#!/usr/bin/rexx say Date() Time() "- bondia." parse version MyVersion say "La versio de Rexx es {" || MyVersion || "}."
Portability

You better use

#!/usr/bin/env bash

Or for whatever the language such as for Perl

#!/usr/bin/env perl
Id

To identify in a log file who is writing into it, we shall use

echo "+++ [`date -R`] +++ ("$0") +++" >> $mylog

We can use this line to "init" the logfile ...


built-in commands

bash reference manual

echo versus printf

printf has more formatting options

The difference is that echo sends a newline at the end of its output.


bash shell functions

A bash function is essentially a set of commands that can be called numerous times.

bash shell function sample

function_name () { sz_NomFitxer=$1 # get first param sz_File_Size=$2 # get second param # some commands myRC=0 return $myRC # to make this clear: return (like exit) can only take a value from 0-255 }

linux.ize

Call your function without parenthesis neither commas :

iRC=function_name $myFileName $myFileSize
bash shell function returning values

Bash functions, unlike functions in most programming languages, do not allow you to return a value to the caller. When a bash function ends its return value is its status: zero for success, non-zero for failure.

To return values, you can set a global variable with the result, or use command substitution, or you can pass in the name of a variable to use as the result variable.

The simplest way to return a value from a bash function is to just set a global variable to the result. Since all variables in bash are global by default this is easy:

function myfunc() { myresult='some value' } myfunc echo $myresult

The other way to return a value is to write your function so that it accepts a variable name as part of its command line and then set that variable to the result of the function:

function myfunc() { local __resultvar=$1 local myresult='some value' eval $__resultvar="'$myresult'" } myfunc result echo $result

linux journal

This is my way :

nicolau@mars:~/eines/proves$ cat 3_prova_return_from_function.sh #!/bin/bash function la_meva_funcio { echo "+++ funcio, param ("$1")." let myRC=$1+5 return $myRC } echo "anem" la_meva_funcio 22 rv=$? echo "tornem" $rv exit 0

El resultat :

nicolau@mars:~/eines/proves$ ./3_prova_return_from_function.sh anem +++ funcio, param (22). tornem 27

Amunt! Top Amunt!
bash shell parameters

pi@odin:~/eines $ cat 2_mostra_params.sh #!/bin/bash echo Script name: $0 echo We have $# arguments j=0 for i; do let j=j+1 echo 'Parameter '$j' is ' $i done

A simple sample - "sh userReg-positional-parameter.sh john 25 'John Smith'"

echo "Username: $1"; echo "Age: $2"; echo "Full Name: $3";

A more complete, with flags - "sh userReg-flags.sh -f 'John Smith' -a 25 -u john"

while getopts u:a:f: flag do case "${flag}" in u) username=${OPTARG};; a) age=${OPTARG};; f) fullname=${OPTARG};; esac done echo "Username: $username"; echo "Age: $age"; echo "Full Name: $fullname";
Special parameters

Llegim aqui :

Com passar un string com 1 sol parametre

El truc es canviar "IFS", el "internal field separator" :

export IFS='-' # canviem el Internal Field Separator per poder passar string com a parametre # define possible commands we can use : sz_CMD_IPS='ip ; neighbor ; print detail' # nodes conectats a un super-node sz_CMD_FW_USR='ip ; firewall ; address-list ; print detail' # usuaris que tenen sortida a la Fibra Optica sz_PXY_USERS='ip ; proxy ; access ; print detail' # usuaris privilegiats del Web Proxy, o sigui, amb acces a 172.xxx function accedir { # +++ define function sz_SERVIDOR=$1 sz_COMMAND=$2 sshpass -p "my_pwd" ssh -o StrictHostKeyChecking=no $my_USER@$sz_SERVIDOR $sz_COMMAND return 0 } # --- define function TaborST1AP1=10.139.130.129 TaborST1AP3=10.139.238.129 TaborRD1AP1=10.139.238.225 TaborRD1AP2=10.139.239.65 TaborRD1AP3=10.139.238.97 CampanarST1AP1=10.139.130.65 CementiriAP1=10.139.130.161 CanCollAP1=10.139.130.193 accedir $CampanarST1AP1 $sz_PXY_USERS exit 0
Subroutines
mate@punt-omnia:~/eines/ssh$ cat scan.sh #!/bin/bash # https://gist.github.com/arunoda/7790979 - utility which allows you to provide the ssh password without using the prompt MY_USER="usuari" FN_O="out.txt" # erase old output file echo ' ' > $FN_O function accedir { # +++ define function SERVIDOR=$1 szMSG="+++ +++ [`date -R`] +++ +++ Accedir al server {"$SERVIDOR"}." echo $szMSG >> $FN_O sshpass -p "my.pwd" ssh -o StrictHostKeyChecking=no $MY_USER@$SERVIDOR 'ip ; neighbor ; print detail' >> $FN_O ls -al $FN_O return 0 } # --- define function TaborST1AP1=10.139.130.129 CanCollAP1=10.139.130.193 accedir $TaborST1AP1 accedir $CanCollAP1 exit 0

Amunt! Top Amunt!
jobs in background

"jobs -l" or "jobs -p" show background processes only for current session

nohup, huponexit

"nohup" versus "ampersand"

From bash manpage :
If a command is terminated by the control operator &, the shell executes the command in the background in a subshell. The shell does not wait for the command to finish, and the return status is 0.

From nohup manpage :
nohup - run a command immune to hangups, with output to a non-tty

nohup catches the hangup signal while the ampersand does not.

What is the hangup signal? SIGHUP - hangup detected on controlling terminal or death of controlling process (value: 1).

There is no difference between these launching methods when the shell is configured in a way where it does not send SIGHUP at all.
In case you are using bash, you can use the command specified below to find out whether your shell sends SIGHUP to its child processes or not:

~ $ shopt | grep hupon

Amunt! Top Amunt!
script versioning

To identify the version of the script we are using, we have to use :

#!/bin/bash # v 1.m - use mutt myVer="1.m" szME="+++ [$myTm] +++ [$HOSTNAME] +++ [$(whoami)] +++ [$0] +++ v ($myVer) +++" echo -e "$szME" >> $myLog 2>&1

Amunt! Top Amunt!
bash conditional expressions

See manual, samples (binary, string, integer) ;

We can test of : files, strings and numbers

Logical operators are : and, or and not

Expressions may be combined using the following operators, listed in decreasing order of precedence - see "man bash"

( expression ) Returns the value of expression. This may be used to override the normal precedence of operators. ! expression True if expression is false. expression1 && expression2 True if both expression1 and expression2 are true. expression1 || expression2 True if either expression1 or expression2 is true.

The opening bracket [ is actually a command :

$ which [ /usr/bin/[
numeric comparison operators

Possible comparacions :

arg1 -eq arg2 True if arg1 equals arg2 arg1 -ne arg2 True if arg1 is not equal to arg2 arg1 -lt arg2 True if arg1 is less than arg2 arg1 -le arg2 True if arg1 is less than or equal to arg2 arg1 -gt arg2 True if arg1 is greater than arg2 arg1 -ge arg2 True if arg1 is greater than or equal to arg2

Exemple (one-liner) :

$ X=1 ; if [ $X -eq 1 ] ; then echo "X equals 1" ; else echo "X does not equal 1" ; fi X equals 1

opensource

String comparison operators

-z string True if the length of string is zero -n string True if the length of string is non-zero string1 == string2 True if the strings are equal; When used with the [[ command, this performs pattern matching as described above (compound commands). string1 = string2 True if the strings are equal; a single = should be used with the test command for POSIX conformance. string1 != string2 True if the strings are not equal string1 < string2 True if string1 sorts before string2 lexicographically (refers to locale-specific sorting sequences for all alphanumeric and special characters) string1 > string2 True if string1 sorts after string2 lexicographically
logical operations on files

-a file True if file exists -e file True if file exists -d file True if file exists and is a directory -x file True if file exists and is executable -s file True if file exists and has a size greater than zero ; tecadmin -f file True if file exists and is a regular file -n string True if the length of string is non-zero -z string True if the length of string is zero -eq True if EQUAL -ne True if not equal
double conditions

We can test in 2 steps :

#!/usr/bin/env bash FILENAME=myfile.txt if [ -f "${FILENAME}" ]; then if [ -s "${FILENAME}" ]; then echo "File ${FILENAME} exists and not empty" else echo "File ${FILENAME} exists but empty" fi else echo "File ${FILENAME} not exists" fi

... or both at the same time :

echo "make a choice 1" read choice1 echo "make a choice 2" read choice2 if [ "$choice1" == 'y' ] && [ "$choice2" == 'y' ]; then echo "Test Done !" else echo "Test Failed !" fi

Here is a nice one :

#!/bin/bash read x if [ $x == "Y" ] || [ $x == "y" ] then echo "YES" else echo "NO" fi
Verify return code

$? expands to the exit status of the most recently executed foreground pipeline.

See the Special Parameters section of the Bash manual.

rv=$? echo ">>> my return code is" $rv >> $myLog if [ "$rv" -ne 0 ]; then echo "--- mira errors a /var/log/syslog" >> $myLog fi
Verify I am root

#!/bin/ksh if [ `id -u` -ne 0 ] then echo "Must be running as root" exit 1 fi
Verify a file exists

#!/bin/bash FILE=/etc/resolv.conf if [ -f "$FILE" ]; then echo "$FILE exist" else echo "$FILE does not exist" fi

If we want to exit if file does not exist :

#!/bin/bash FILE=/etc/resolv.conf if [[ ! -f $FILE ]] then echo "$FILE does not exist on your filesystem." fi
Verify I have a parameter

#!/bin/bash if [ -z "$1" ] then echo "--- No argument supplied" exit 1 fi

To modify default value :

#!/bin/bash fn="default.value" if [ -n "$1" ] then fn=$1 fi echo "Filename" $fn
nested if conditions

nicolau@mars:~/sebas/python/bot$ cat post_2_bot.sh iSel=$1 echo "Seleccio" $iSel if [[ iSel -eq 0 ]] then echo FER ZERO else if [[ iSel -eq 1 ]] then echo FER U else echo fer resta fi fi
double if conditions

The comparison operator "-ne" is an arithmetic operator, i.e. it compares only integers:

i=7 if [ "$i" -ne 6 ] && [ "$i" -ne 8 ]; then echo 'i is neither 6 nor 8' fi

To compare strings for inequality, use !=:

if [ "$filename" != 'even' ] && [ "$filename" != 'odd' ]; then printf '%s\n' "$filename" fi
create a large string + display string length

nicolau@mars:~/eines/proves$ cat 4_prova_allargar_string.sh #!/bin/bash myVar="a" iCnt=1 while [ $iCnt -le 12 ]; do # 2 exp 12 = 4096 echo "The counter is" $iCnt myVar=$myVar$myVar let iCnt=$iCnt+1 done mySize=${#myVar} # use “#” symbol to get string length echo "("$mySize")." echo "("$myVar")." exit 0

Amunt! Top Amunt!
Envir vars
How to set global envir vars

sebas@r4:~ $ cat /etc/environment SAG_TUSR="t_user" SAG_TPWD="t_pwd"

Compte : no hi pot haver comentaris en aquest fitxer, ni res despres de les cometes de tancar

Few envir values we can use

Use env command to display available ones ...

#!/bin/bash myhost="9.137.164.25" myqos="0" mytopic="bisc/monit/pcs" myid="mosquitto_pubTASK_client" myuser=$USER mymsgid="bisc.TT2.mpc.v1a" myhn=$HOSTNAME myip="$(/sbin/ifconfig eth0 | grep 'inet addr:9' | cut -d: -f2 | awk '{ print $1}')" mydate=`date +"y%Y/m%m/d%d"` mytime=`date +"h%H:m%M"` mymsg="$mymsgid $myhn $myip $mydate $mytime" echo "MyMsg={" $mymsg "}."

Amunt! Top Amunt!
Verify a directory exists
if [ -d "$LINK_OR_DIR" ]; then # use "!" to change it to "not exist" if [ -L "$LINK_OR_DIR" ]; then # It is a symlink! # Symbolic link specific commands go here rm "$LINK_OR_DIR" else # It's a directory! # Directory command goes here rmdir "$LINK_OR_DIR" fi fi

url

Verify a file exists
if [ -e "$FN" ]; then # use "!" to change it to "not exist"

BASH intro to IF. File test operators : url.


Amunt! Top Amunt!
Generate a timestamp - multiple date() forms

Bona url

sebas@T60ubuntu:~/eines/prova_shell$ cat dates.sh #!/bin/bash # input : $1 = directory name myT=$(date +%R) # short time (20:27,01/07/19) - no posa els segons myD=$(date +%D) # short date (20:27,01/07/19) - posa any-dia-mes myT=$(date +"%H:%M:%S") # myT=$(date +"%H:%M:%S%N") # ... microseconds myT=$(date +"%H:%M:%S%3N") # ... miliseconds myD=$(date +"%d/%m/%Y") # short date, 4 digit year, day before month myZ=$(date +%Z) # timezone myDate=`date +"Y%y/M%m/D%d"` myTime=`date +"h%H:m%M:s%S"` tz_SAG="Europe/Madrid" # see /usr/share/zoneinfo, as "America/Los_Angeles" bak_file=$myDate".tgz" dir_dst="/vmfs/volumes/Storage1/backups" fn1=$1"_"$bak_file f_dst=$dir_dst"/"$fn1 echo -e "("$myDate"-"$myTime") +++ ($myT,$myD,$myZ) +++ [$(date '+%Y %b %d %H:%M')] +++\n+++ [`date -R`] +++ "$(TZ=$tz_SAG date)" +++\n+++ Crear {"$f_dst"}" exit 0

La sortida es

sebas@T60ubuntu:~/eines/prova_shell$ ./dates.sh potato (Y19/M01/D07-h20:m27) +++ (20:27,01/07/19,CET) +++ [2019 ene 07 20:27] +++ +++ [Mon, 07 Jan 2019 20:27:05 +0100] +++ lun ene 7 20:27:05 CET 2019 +++ +++ Crear {/vmfs/volumes/Storage1/backups/potato_Y19/M01/D07.tgz}
Best timestamp

myT=$(date +"%H:%M:%S") # myD=$(date +"%d/%m/%Y") # short date, 4 digit year, day before month myStamp=$myD"_"$myT echo ">>> Timestamp is *" $myStamp "*" exit 0
user-function : timestamp

my_timestamp() { date +"%H:%M:%S" }

Later use it :

RC=$? echo ">>> $(my_timestamp) wget rc = ("$RC")."

Amunt! Top Amunt!
Few commands in one line

Combining two or more commands on the command line is also known as “command chaining”.

It can be done in different ways :

url

Sample :

guifi@torrelles:/etc/cron.d$ cat dnsservices # # Regular cron jobs for the dnsservices package # */30 * * * * root cd /etc/bind && /usr/bin/php /usr/share/dnsservices/dnsservices.php >> /var/log/dnsservices/dnsservices.log && /etc/init.d/bind9 reload

Amunt! Top Amunt!
Redirecting Standard Output and Standard Error

See "man bash"

discard all output

The command is :

sebas@pi0alby:~ $ nohup sudo ping 192.168.1.2 &> /dev/null & [1] 15773
stdout and stderr to same file

The &> myfilename construct allows both the standard output (file descriptor 1) and the standard error output (file descriptor 2) to be redirected to the file whose name is the expansion of "myfilename".

This is semantically equivalent to "1> myfilename 2>&1"

Appending ***all***

The format for appending standard output and standard error is:

&>> filename 1>> filename 2>&1 # molt millor, per no tenir problemes amb el "&" (go background)

This is semantically equivalent to

>> filename 2>&1
my redirections

guifi@torrelles:/etc/cron.d$ cat guifi-proxy # # Regular cron jobs for the guifi-proxy package # 55 * * * * root /usr/share/guifi-proxy/guifi-proxy.sh >> /var/log/guifi-proxy/guifi-proxy.log 2>&1;

url

why it is 2>&1 and not 2>>&1

Lets try

$ curl www.google.com 1> a.txt 2> b.txt

Take a look on "error" output from curl, written into b.txt :

sag@odin:/tmp/sag $ cat b.txt % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 12469 0 12469 0 0 116k 0 --:--:-- --:--:-- --:--:-- 115k

So, we always have output on stderr ... Now we do

sag@odin:/tmp/sag $ rm a.txt sag@odin:/tmp/sag $ echo "##sag##" >> a.txt && curl www.google.com 1>> a.txt 2>&1 sag@odin:/tmp/sag $ echo "##sag##" >> a.txt && curl www.google.com 1>> a.txt 2>&1 sag@odin:/tmp/sag $ echo "##sag##" >> a.txt && curl www.google.com 1>> a.txt 2>&1 sag@odin:/tmp/sag $ echo "##sag##" >> a.txt && curl www.google.com 1>> a.txt 2>&1 sag@odin:/tmp/sag $ cat a.txt | grep '##sag##' | wc 4 7 578

So, "2>&1" does not mean "replace" but "place stderr where stdout goes"

TEE

Use the tee command to display on screen and simultaneously redirect to file !

heredoc

To write to a file an explicit text, use "heredoc" :

#!/bin/sh FILE="/path/to/file" /bin/cat <<EOM >$FILE text1 text2 # This comment will be inside of the file. The keyword EOM can be any text, but it must start the line and be alone. text4 EOM

Amunt! Top Amunt!
Concepts I have missing
How to know own directory when running a shell from crontab ?

Problem : if the script writes a file and is executed from crontab, the file is written into /home/<user>

Solution :

cd "$(dirname "$0")";

Amunt! Top Amunt!
Temporary files

Often, there will be times when you need to create a temporary file. Once the program's purpose is completed, the file is often deleted. When you create a file, you have to give it a name. The problem is, the file you create, must not already existing in the directory you are creating it in. Otherwise, you could overwrite important data. In order to create a unique named temporary file, you need to use the "$$" symbol, by either prefixing, or suffixing it to the end of the file name. Take for example, you want to create a temporary file with the name hello. Now there is a chance that the user who runs your program, may have a file called hello, so that would clash with your program's temporary file. By creating a file called hello.$$, or $$hello instead, you will create a unique file. Try it:

xconsole$ touch hello xconsole$ ls hello xconsole$ touch hello.$$ xconsole$ ls hello hello.689

There it is, your temporary file.


Amunt! Top Amunt!
Verify return code from a MQ program

#!/bin/bash fn="dades.txt" ./myget QL.SIT P9111 rc=$? if [ $rc -eq 0 ] then echo "+++ rc eq 0 : exit status no messages." else echo "+++ rc ne 0 : exit status ($rc). There are messages in the queue." fi

Compte !

The return from main() is handed to exit(). From "man 3 exit" (macOSX, but other UNIX are essentially the same): [...] void exit(int status); [...] make the low-order eight bits of the status argument available to a parent process which has called a wait(2)-family function.

group unix-basics


Amunt! Top Amunt!
Multiply in bash

MSGLNG=$(expr 10 \* 1024) echo "... each " $MSGLNG " bytes long."

An alternative to using expr, is to enclose the arithmetic operation inside $((...)). This is different from $(...). The number of brackets will tell you that. Let us try it:

#!/bin/bash x=8 # initialize x to 8 y=4 # initialize y to 4 # now we assign the sum of x and y to z: z=$(($x + $y)) echo "The sum of $x + $y is $z"

Amunt! Top Amunt!
Searching for a substring

First try :

#!/bin/bash if [[ "$sz_IP" =~ "172." ]]; then echo "IP ("$sz_IP") is internal" else echo "IP ("$sz_IP") is public" fi

If we have a line like

#90# Darrera generacio : {2020-09-05 14:00:05}.

The we can do url :

szDate=$( cat IP_PI0.HTM | grep "#90#" | cut -d'{' -f 2 | cut -d'}' -f 1 ) echo ">>> Last date" $szDate

Amunt! Top Amunt!
Reading user input
#!/bin/bash # gets the name of the user and prints a greeting echo -n "Enter your name: " read user_name # the user did not enter anything: if [ -z "$user_name" ]; then echo "You did not tell me your name!" exit fi echo "Hello $user_name!"

Amunt! Top Amunt!
incrementing a global var

#!/bin/bash iCNT=0 function accedir { iCNT=$(($iCNT+1)) szURL=$1 echo "($iCNT) URL { $szURL }" return 0 } accedir https://my.net accedir https://pi.ink exit 0

Amunt! Top Amunt!
Virgueries grafiques
Display all box-drawing chars

#!/bin/bash char=( 6a 6b 6c 6d 6e 71 74 75 76 77 78 ) for i in ${char[*]} do printf "0x$i \x$i \e(0\x$i\e(B\n" done

Resultat :

sebas@minie:~/dades/bash$ ./box_chars.sh 0x6a j ┘ 0x6b k ┐ 0x6c l ┌ 0x6d m └ 0x6e n ┼ 0x71 q ─ 0x74 t ├ 0x75 u ┤ 0x76 v ┴ 0x77 w ┬ 0x78 x │

url

Caracters especials - backslash escapes
#!/bin/bash echo -e "\n +++ [`date -R`] \t is ..." ; "-e" means "allow backslash escapes"
Colorejar el texte

ANSI codes :

Black 0;30 Dark Gray 1;30 Red 0;31 Light Red 1;31 Green 0;32 Light Green 1;32 Brown/Orange 0;33 Yellow 1;33 Blue 0;34 Light Blue 1;34 Purple 0;35 Light Purple 1;35 Cyan 0;36 Light Cyan 1;36 Light Gray 0;37 White 1;37

#!/bin/bash # ANSI escape codes GREEN='\033[0;32m' RED='\033[0;31m' CYAN="\[\033[0;36m\]" GRAY="\[\033[1;30m\]" NOC='\033[0m' # No Color echo -e "--- [`date -R`] ($sz_descr) ($sz_IP)\t is ${RED}down${NOC}"

code, ANSI

Exemple de us : sebas@minie:~/dades/btc$ ./btc.sh

Colorejar el prompt

Hem de modificar .bashrc

  1. descomentar "force_color_prompt"

vitux


Amunt! Top Amunt!
Rare string operations

This method relies on enclosing a variable name in curly braces, then aplying a special operator to achieve a particular result.

Operator "#" means "delete from the left, to the first case of what follows."

$ x="This is my test string." $ echo ${x#* }

Result :

is my test string.

Operator "##" means "delete from the left, to the last case of what follows."

$ x="This is my test string." $ echo ${x##* }

Result :

string.

Operator "%" means "delete from the right, to the first case of what follows."

$ x="This is my test string." $ echo ${x%* }

Result :

This is my test

Operator "%%" means "delete from the right, to the last case of what follows."

$ x="This is my test string." $ echo ${x%%* }

Result :

This

url

Var/string length

See string manipulation routines

myvar='Généralités' chrlen=${#myvar} # calculate char length oLang=$LANG oLcAll=$LC_ALL LANG=C LC_ALL=C bytlen=${#myvar} # calculate byte length LANG=$oLang LC_ALL=$oLcAll printf "%s is %d char len, but %d bytes len.\n" "${myvar}" $chrlen $bytlen will render Généralités is 11 char len, but 14 bytes len.

Amunt! Top Amunt!
Shell functions

See man bash and find(FUNCTIONS) : "functions are executed in the context of the current shell".
In file ~/funcions/sagnd, write :

nd() { # shell function - creates and cwd's a directory if [ ! -d $1 ]; then mkdir $1 fi if [ -d $1 ]; then cd $1 fi }

And in ~/.bash_profile include source ~/funcions/sagnd.

My Alias

The root profile is located at /root/.bashrc, the global one, at /etc/bashrc.

Private profile is ~/.bash_aliases.

echo "+++ .bash_aliases - v1.1d 20200428" nd() { mkdir $1 && cd $1; } web2() { clear && cd /home/nicolau/sebas/_local_tinet_files; } # User specific aliases and functions if [ -x /usr/bin/dircolors ]; then alias ls='ls --color=auto' alias grep='grep --color=auto' alias fgrep='fgrep --color=auto' alias egrep='egrep --color=auto' fi alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' alias l='ls -CF' alias la='ls -A' alias ll='ls -alF' alias ls='ls -als --color=auto' alias busca='grep -i -s -m 1' // use as "busca '&&' *" alias busca2='grep -rnwl . -e' // use as "busca2 txt" alias cd..='cd ..' alias cls='clear' alias dels='sudo rm ./* -rf' alias df='df -h | grep sd' // dont show virtual devices alias dirs='sudo du . --max-depth=1 -m -h' alias dirs="du -hs * | sort -rh | head -5" // show 5 largest directories tecmint alias findbig='find / -size +100000000c 2> /dev/null' // files bigger than 100 MB alias fm='nautilus --browser . &' // as "start ." in guindous alias last='last -aiFn5' alias lok="gnome-screensaver-command -l &" // lock the computer alias md=mkdir alias mira="ps -ef | grep -v grep | grep" alias mydns='cat /etc/resolv.conf' // display DNS alias mydns='systemd-resolve --status' // ... using Network Manager alias mydns='nmcli device show wlp3s0 | grep DNS" // get interface name from ifconfig alias mywifi='/sbin/iwgetid' // show ESSID alias myfs='df -h | grep sdb' alias mygw='cat /etc/network/interfaces' // display GW alias mygw='route -n' // ... using Network Manager alias myhost='host myraspiodin.hopto.org' alias myip='curl -m 2 -s icanhazip.com' // display external IP - maybe "curl -m 2 -s http://checkip.amazonaws.com" is better alias myopsys='cat /etc/os-release' alias mysysop='lsb_release -a' alias mynoip2='host xarxatorrelles.ddns.net' alias myports='sudo netstat -peanut | grep' // display open ports alias myproxy='cat /etc/environment | grep proxy' alias mypxe='sudo systemctl status tftpd-hpa' alias myrestart='sudo cat /var/log/syslog | grep "Booting Linux"' alias myubuntu='lsb_release -a' alias myusers='sudo tail -f /var/log/auth.log' alias mywifis='nmcli device wifi list' // show wifis around alias pxy-users='squidclient mgr:client_list' alias pi='sudo ping 8.8.8.8' alias r0='ssh sebas@192.168.1.222' // ssh to piZero alias r3='ssh sag@192.168.1.123' alias slog='sudo tail -f /var/log/syslog' alias testmutt='echo "my BODY" | mutt -d 5 -s "my SUBJECT" -- desti@gmail.com' alias web='clear && cd /home/nicolau/sebas/_local_tinet_files' alias whoiam=whoami alias wscan='sudo iwlist wlan0 scanning | grep ESSID' // display visible wifi networks echo "--- .bash_aliases"

After modifying .bash_aliases, run this command to get updated envir : source ~/.bash_profile

pi@raspberrypi:~ $ source ~/.bash_profile -bash: /home/pi/.bash_profile: No such file or directory

Solucio : "exec bash" o source ~/.bashrc

After defining an alias, test it by running "alias <name>" afterward

Multiple commands in an alias for bash

alias sequence='command1 -args && command2 -args'

See command chaining

Interesting commands

Add this to your ~/.bashrc

extract () { if [ -f $1 ] ; then case $1 in *.tar.bz2) tar xvjf $1 && cd $(basename "$1" .tar.bz2) ;; *.tar.gz) tar xvzf $1 && cd $(basename "$1" .tar.gz) ;; *.tar.xz) tar Jxvf $1 && cd $(basename "$1" .tar.xz) ;; *.bz2) bunzip2 $1 && cd $(basename "$1" /bz2) ;; *.rar) unrar x $1 && cd $(basename "$1" .rar) ;; *.gz) gunzip $1 && cd $(basename "$1" .gz) ;; *.tar) tar xvf $1 && cd $(basename "$1" .tar) ;; *.tbz2) tar xvjf $1 && cd $(basename "$1" .tbz2) ;; *.tgz) tar xvzf $1 && cd $(basename "$1" .tgz) ;; *.zip) unzip $1 && cd $(basename "$1" .zip) ;; *.Z) uncompress $1 && cd $(basename "$1" .Z) ;; *.7z) 7z x $1 && cd $(basename "$1" .7z) ;; *) echo "don't know how to extract '$1' ..." ;; esac else echo "'$1' is not a valid file!" fi }

Now just type "extract filename" and you're golden.

unrar details

If you have 3 files

nom.part1.rar nom.part2.rar nom.part3.rar

Then the way to uncompress them all is

$ unrar x nom.part1.rar

If you dont have "unrar" in your system, just install it by "sudo apt install unrar"


SFTP and SCP - tips and problems
SCP - backup remote directory

sebas@minie:~/backups/r0/python$ scp -rp pi@r0:/home/pi/python . $ scp -r user@your.server.example.com:/path/to/foo /home/user/Desktop/ By not including the trailing '/' at the end of foo, you will copy the directory itself (including contents), rather than only the contents of the directory. use -p to preserve file modification times, permissions, etc!

stackoverflow,

SCP - configuration connection problem

If you receive a "message too long" when using SFTP or SCP, as :

nicolau@mars:~/sebas/rspi/backups/r4/20220403/home/sebas/.config/systemd/user$ sftp pi@r4 pi@r4's password: Received message too long 724249376

... then you have to clean ".bashrc" of "echo" messages, as :

# --- scp --- echo "+++ .bashrc - v1.1a 20210518" # --- scp --- echo "--- .bashrc - v1.1a 20210518"

Amunt! Top Amunt!
do FTP from shell

mate@punt-omnia:~/nodejs-projects/timer/send_page$ cat send_page.sh #!/bin/bash # crontab starts this job with no log specified LogFile="/home/mate/logs/send_page.log" # set timestamp echo "+++ [`date -R`] +++ ("$0") +++ FTP 3 pages v3.2 +++" >> $LogFile FileName1='/home/mate/nodejs-projects/timer/public/pagina.html' FileName2='/home/mate/eines/rexx/scan_guifi/qq_127.html' FileName3='/home/mate/eines/ssh/conectats.html' HostName='files.000webhost.com' myUser='torrelles-guifi' myPwd='my-pwd' # Use the ftp command with the -inv switches. # -i turns off interactive prompting # -n restrains FTP from attempting the auto-login feature # -v enables verbose and progress function ftp_it { ftp -inv $HostName >> $LogFile 2>&1 << END_SCRIPT quote USER $myUser quote PASS $myPwd binary put $1 $2 quit END_SCRIPT return 0 } ftp_it $FileName1 public_html/pagina.html ftp_it $FileName2 public_html/qq_127.html ftp_it $FileName3 public_html/conectats.html echo "--- [`date -R`] +++ ("$0") +++ FTP 3 pages v3.2 ---" >> $LogFile exit 0

Compte : queda el procés engegat (en cas d'error ?)

mate@punt-omnia:~/nodejs-projects/timer/send_page$ ps -ef | grep send_page.sh | wc 13 148 1741

scripting ftp

Error here-document :


TCPIP.shell

Get all TCP/IP data : ip, gateway, dns ...

/home/mate/bin/tcpip(.sh)

T60 : /usr/local/bin/tcpip


IF-THEN-ELSE

#!/bin/bash echo -n "Enter a number: " read VAR if [[ $VAR -gt 10 ]] then echo "The variable is greater than 10." else echo "The variable is equal or less than 10." fi
one liner

if [ -f "/usr/bin/wine" ]; then export WINEARCH=win32; fi
Conditionals with variables

#!/bin/bash T1="foo" T2="bar" if [ "$T1" = "$T2" ]; then echo expression evaluated as true else echo expression evaluated as false fi

TLDP 7, TLDP 6.


Conditional statements
IF statement

echo "Script name: $0" NumArg=$# echo "We have ($NumArg) arguments" # set defaults szStart="1652775000" szEnd="1652775045" outFN='/dev/null' if [ "$NumArg" -gt 0 ]; then szStart=$1 fi if [ "$NumArg" -gt 1 ]; then szEnd=$2 fi if [ "$NumArg" -gt 2 ]; then outFN=$3 fi echo ">>> export using start ($szStart) and end ($szEnd) into ($outFN)."
WHILE loop and CASE statement

while : do clear echo -n 'Questions? ' read x case $x in a) echo a ;; b|c) echo b or c ;; q) break ;; *) echo Invalid command \"$x\" ;; esac done

url

while FOREVER loop

Explicit :

#!/bin/bash while true do echo "Press [CTRL+C] to stop" sleep 1 done

One-liner :

while :; do traceroute -n 10.139.239.102 ; sleep 1 ; done
WHILE sample

#!/bin/bash myCOUNTER=0 while [ $myCOUNTER -lt 10 ]; do echo "The counter is" $myCOUNTER let myCOUNTER=$myCOUNTER+1 done echo "End counter is" $myCOUNTER

A very complete WHILE loop sample

WHILE READ environment

Atenció : el "while read" s'executa dins un sub-shell que es genera amb el "CAT nom" amb una "pipeline"
Així, "$COUNTER" valdrà 0 després del "done" .. excepte si ho agrupem amb uns parentesi : "(" i ")"

Metode correcte aqui :

#!/bin/bash cnt=0 cat input.data | ( while read do let cnt++; echo "Counting to $cnt" done echo "Exit count is $cnt" )
*** while complete code ***

sebas@pi0alby:~/python/telegram $ cat prova_bash.sh #!/bin/bash acabat=0 rebut=0 numErr=0 maxErr=5 while [ $acabat -ne 1 ]; do myIP=$( curl -m 2 -s icanhazip.com ) RC=$? if [ $RC -eq 0 ]; then let acabat=1 let rebut=1 else let numErr=$numErr+1 if [ $numErr -eq $maxErr ]; then let acabat=1 else sleep 5 fi fi done echo "Acabat "$acabat", rebut "$rebut", numerr "$numErr"." if [ $rebut -eq 1 ]; then echo "+++ MyIP {"$myIP"}." fi exit 0
UNTIL sample

#!/bin/bash myCOUNTER=20 until [ $myCOUNTER -lt 10 ]; do echo Counter $myCOUNTER let myCOUNTER-=1 done

{repos}
BASH details

Feel free to send me your own !

Display time & date, log to file and to syslog

#!/bin/bash fn=/home/user/logs/sebasCmd.log date_name=`date +"%y/%m/%d"` time_name=`date +"%H:%M"` szId="("$time_name") +++ ("$0") +++ today is {"$date_name"} - log in file ("$fn")." # 1st on screen echo "$szId" # 2nd on own log echo "$szId" >> $fn # 3rd on system log logger -p user.info "$szId" exit 0
Find large files
#!/bin/bash find / -size +400000000c
Debug a shell

The "set -x" parameter to ksh is a useful debug feature to print commands and their arguments when executing a ksh script.

So, if you to add this on the first line, this will produce some interesting output information:

#!/bin/bash -x exit 0

If you want to debug a shell just once, run it this way :

ksh -x script_name - it is the same as "ksh script_name" with "set -x" in the script itself

TLDP

Display directories size (1st level)

#!/bin/bash du / -m --max-depth=1
Display largest directories at local

alias dirs='du -hs * | sort -rh | head -5'
Display Notes clients

#!/bin/bash echo "Numero de usuarios :" netstat -ano | grep 1352 | wc -l echo "Las IPs de los usuarios son :" netstat -ano | grep 1352
Veure distribució Linux

#!/bin/bash cat /etc/issue
bash return value from a program

In bash, the return value of a program is stored in a special variable called $?.
Run this shell with an existing "/dada" and with a non-existing "/dada" directory:

#!/bin/bash cd /dada &> /dev/null rc=$? echo $rc
get RC from PING or WGET
sebas@T60ubuntu:~/eines/tronc$ cat scan_tronc.sh #!/bin/bash export IFS='-' # proxy Campanar : export http_proxy=http://10.139.130.65:3128 export https_proxy=https://10.139.130.65:3128 # output file myOF="out.txt" # definim la funcio function accedir { sz_IP=$1 sz_descr=$2 echo ">>> acces a " $sz_descr", ip" $sz_IP curl -v -k -L http://$sz_IP/ > $myOF 2>&1 rv=$? if [ $rv -eq 0 ]; then # check the exit code echo -e "+++ [`date -R`] ($sz_IP)\t is up" else echo -e "--- [`date -R`] ($sz_IP)\t is down" # echo -e == allow backslash escapes fi return 0 } # accedir # definim les ips router_campanar_tabor="172.25.66.4" antena_campanar_tabor="172.25.66.3" # accedim a les ips accedir $router_campanar_tabor "Router del Campanar al Tabor" accedir $antena_campanar_tabor "Antena del Campanar al Tabor" exit 0
Read file into bash array

#!/bin/bash fn=$1 echo "Lets read ("$fn") file." cnt=0 while read curline; do MY[$cnt]="$curline" cnt=$(($cnt+1)) done < $fn echo "Lines :" $cnt "Elements :" ${#MY[@]} echo "Contingut :" ${MY[@]} ELEM=${#MY[@]} for (( i=0 ; i<ELEM; i++ )); do echo "$i:" ${MY[${i}]} done

url

#!/bin/bash aVar1=() aVar2=() # initialize arrays while read var1 var2 do aVar1+=( "$var1") aVar2+=( "$var2") done < file.txt # ${aVar1[@]} now contains all $var1 values, # ${aVar2[@]} now contains all $var2 values.

url

Trapping Control-C

#!/bin/bash # trap ctrl-c and call ctrl_c() trap ctrl_c INT function ctrl_c() { echo "** Trapped CTRL-C" exit 0 } for i in `seq 1 5`; do sleep 1 echo -n "." done
File parsing

Elementary

#!/bin/bash cat peptides.txt | while read line do # do something with $line here done

With some parsing

#!/bin/bash cat file | while read a b c; do #process ... likely: echo "${a//search/replace} $b $c"; # etc... done
ps details

"forest" :

$ ps -e -o pid,args --forest
ps and kill

A nice one:

#!/bin/bash while : do # find parent ids PIDS="`ps -eao bsdtime,pid,command | egrep -v egrep | egrep 'processname' | awk '{print $2}'`" count=0 # loop through ppids and look for children for j in ${PIDS} do #echo "Parent process = $j" CPID="`ps -ef | awk '$3 == J {print $2}' J=$j`" for i in ${CPID} do #echo "Child process = $i" let count++ done done

Perl parsing ps fwaux output

Simple :

[root@rhv6-64b reserves]# ps -ef | grep mongod | grep -v grep root 23517 1 0 15:06 ? 00:00:04 /usr/bin/mongod --rest --config /etc/mongod.conf [root@rhv6-64b reserves]# ps -ef | grep mongod | grep -v grep | awk '{print $1}' root [root@rhv6-64b reserves]# ps -ef | grep mongod | grep -v grep | awk '{print $2}' 23517

Another

$ ps -A -o pid,cmd | grep xxx | grep -v grep | head -n 1 | awk '{print $1}' $ ps | grep '/usr/bin/mintty' | head -n 1 | awk '{print $1}' [root@rhv6-64b reserves]# ps -A -o pid,cmd | grep mongod | grep -v grep | head -n 1 | awk '{print $1}' 23517 [root@rhv6-64b reserves]# ps -A -o pid,cmd | grep mongod | grep -v grep 23517 /usr/bin/mongod --rest --config /etc/mongod.conf
Feed ps output into kill command

Unix shell :

#!/bin/bash tokill=$(ps -ax | grep -- "$1" | grep -v grep | awk '{print $1}') if [[ -n $tokill ]] then kill $tokill fi

pkill <process name> or killall <process name> if there are multiple instances and/or child processes !

Pràctiques : "T400:\\Linux\bash\"

Matem "node"

Es comode tenir :

sag@odin $ cat /home/sag/express-sendfile/atura.sh #!/bin/bash toKILL=$(ps -ef | grep node | grep -v grep | awk '{print $2}') echo "want to kill ($toKILL)." if [[ -n $toKILL ]] then kill $toKILL fi exit 0
Justify line to given length

#!/bin/bash ten=" " forty="$ten$ten$ten$ten" y="very short text" y="${y:0:40}${forty:0:$((40 - ${#y}))}" echo "'${y}'" mylng=${#y} echo "char length" $mylng

Output :

'very short text ' char length 40

Amunt! Top Amunt!
single quotes vs double quotes

From bash manual :

Examples :

szIP="IPs : ext {$ipvariable}, int wlan0 {$myip}" szSubject="$szHora - $szIP" szBody='ODIN-002, ('$szHora'), ips ('$szIP'), host ('$HOSTNAME'), wifi ('$nom_wifi'), shell ('$0').'

If you want to write double quotes into output string, you have to "escape" them by backslash :

coding szOut="{\"chat_id\": \"${ID}\", \"text\": \"$MENSAJE\", \"disable_notification\": true}" produces +++ szOut='{"chat_id": "314587090", "text": "Pi0 saluda.", "disable_notification": true}'

See shell expansions

if a=apple then # | Expression | Result | Comments ---+-------------+-------------+-------------------------------------------------------------------- 1 | "$a" | apple | variables are expanded inside "" 2 | '$a' | $a | variables are not expanded inside '' 3 | "'$a'" | 'apple' | '' has no special meaning inside "" 4 | '"$a"' | "$a" | "" is treated literally inside ''

url

Strange expansion

nicolau@mars:~/eines/bash$ cat prova.sh #!/bin/bash my_IP="1.2.3.4" szOut="*** today my IP is {$my_IP} ***" echo $szOut echo "$szOut" exit 0 nicolau@mars:~/eines/bash$ ./prova.sh prova.sh today my IP is {1.2.3.4} prova.sh *** today my IP is {1.2.3.4} ***
diferencies [[ vs [ vs ( vs ((

url

quotes samples

szIP="IPs : ext {$ipvariable}, int wlan0 {$myip}" szSubject="$szHora - $szIP" szBody='ODIN-002, ('$szHora'), ips ('$szIP'), host ('$HOSTNAME'), wifi ('$nom_wifi'), shell ('$0').' produces + szIP='IPs : ext {83.38.34.204}, int wlan0 {192.168.1.123}' + szSubject='20:09,08/02/20 - IPs : ext {83.38.34.204}, int wlan0 {192.168.1.123}' + szBody='ODIN-002, (20:09,08/02/20), ips (IPs : ext {83.38.34.204}, int wlan0 {192.168.1.123}), host (odin), wifi (wlan0 ESSID:"a22"), shell (./snd_1.sh).'

This is, if we use doble quote, the $value gets expanded.

If we use single quote and want $value to be evaluated, we have to put it outside the single quotes.


own global tool

pi@R4:/usr/local/bin $ ls 0 lrwxrwxrwx 1 root root 36 Jun 5 2022 atg -> /home/pi/python/telegram/msg_a_tg.sh

basj jq command

jq tool is used to read JSON data.

linux hint


cut and sed and awk
awk - pattern scanning and processing language

sebas@minie:~$ df -h Filesystem Size Used Avail Use% Mounted on /dev/nvme0n1p5 425G 220G 184G 55% / /dev/nvme0n1p1 96M 52M 45M 54% /boot/efi sebas@minie:~$ df -h | grep n1p5 | awk '{print $3}' 220G
cut - remove sections from each line of files

sebas@minie:~$ df -h Filesystem Size Used Avail Use% Mounted on /dev/nvme0n1p5 425G 220G 184G 55% / /dev/nvme0n1p1 96M 52M 45M 54% /boot/efi sebas@minie:~$ df -h | grep n1p5 | cut -d ' ' -f5 # Zach 220G
sed - stream editor for filtering and transforming text

Line endings

I has a file like this :

sebas@minie:~/dades/rexx/tinet$ cat convertir.rex #!/usr/bin/rexx /* trace ?r */

Pointing at

sebas@minie:~/dades/rexx/tinet$ which rexx /usr/bin/rexx

But there was some strange problem :

sebas@minie:~/dades/rexx/tinet$ ./convertir.rex bash: ./convertir.rex: /usr/bin/rexx^M: bad interpreter: No such file or directory

The ^M indicates the source of the problem : Windows line endings.

Solution : using SublimeText, go to "View->Line Endings" and select "Unix" and save the file.

Stack Iverflow


a bash client for an REST API

The server is coded in python

The client is quite straightforward - Gemini "write a minimal REST client in bash"

sebas@minie:~/dades/bash/rest$ cat rest_client.sh #!/bin/bash # Minimal REST Client in Bash # $ ./rest_client.sh post http://192.168.1.147:5000/upload 1212 # **** ****** # Function to perform a GET request get() { url="$1" echo "Use curl to perform the GET request and jq to format the JSON output" curl -s "$url" # | jq } # Function to perform a POST request post() { url="$1" data="$2" # Use curl to perform the POST request with the given data curl -s -X POST -H "Content-Type: text/plain" -d "$data" "$url" # | jq } # Function to perform a PUT request put() { url="$1" data="$2" echo "Use curl to perform the PUT request with the given data" curl -s -X PUT -H "Content-Type: application/json" -d "$data" "$url" # | jq } # Function to perform a DELETE request delete() { url="$1" # Use curl to perform the DELETE request curl -s -X DELETE "$url" # | jq } # Function to display help message help() { echo "Usage: rest_client.sh <command> <url> [data]" echo "Commands:" echo " get <url> : perform a GET request" echo " post <url> <data> : perform a POST request with data" echo " put <url> <data> : perform a PUT request with data" echo " delete <url> : perform a DELETE request" echo " help : display this help message" echo "" echo "Example:" echo " rest_client.sh get https://jsonplaceholder.typicode.com/todos/1" echo " rest_client.sh post https://jsonplaceholder.typicode.com/todos '{\"title\": \"foo\", \"completed\": false}'" } # Check if command is provided if [ $# -eq 0 ]; then help exit 1 fi # Parse the command and arguments command="$1" url="$2" data="$3" echo ">>> command is : " $command echo ">>> url is : " $url echo ">>> data is : " $data # Perform the appropriate action based on the command case "$command" in "get") if [ -z "$url" ]; then echo "Error: URL is required for GET request." help exit 1 fi get "$url" ;; "post") if [ -z "$url" ] || [ -z "$data" ]; then echo "Error: URL and data are required for POST request." help exit 1 fi post "$url" "$data" ;; "put") if [ -z "$url" ] || [ -z "$data" ]; then echo "Error: URL and data are required for PUT request." help exit 1 fi put "$url" "$data" ;; "delete") if [ -z "$url" ]; then echo "Error: URL is required for DELETE request." help exit 1 fi delete "$url" ;; "help") help ;; *) echo "Error: Invalid command '$command'." help exit 1 ;; esac exit 0

Dubtes

Quina diferencia hi ha ?

if [ arg1 operator arg2 ] ; then list if [[ arg1 operator arg2 ]] ; then list

url

2 TB - permission denied - trailing "+" in file permissions

nicolau@mars:/media/nicolau/sd2gb$ sudo cat "1" > 1.txt bash: 1.txt: Permission denied nicolau@mars:/media/nicolau/sd2gb$ ls total 8 4 drwxr-xr-x 2 root root 4096 Mar 9 2021 . 4 drwxr-x---+ 4 root root 4096 Apr 16 12:50 .. nicolau@mars:/media/nicolau$ ls total 16 4 drwxr-x---+ 4 root root 4096 Apr 16 12:50 . 4 drwxr-xr-x 3 root root 4096 Apr 6 2020 .. 4 drwxr-xr-x 2 root root 4096 Aug 29 2021 ntfs 4 drwxr-xr-x 2 root root 4096 Mar 9 2021 sd2gb

The "+" indicates that there is an ACL (Access Control List) entry associated with the file.

stack overflow,

nicolau@mars:/media/nicolau/sd2gb$ getfacl -a .. # file: .. # owner: root # group: root user::rwx user:nicolau:r-x group::--- mask::r-x other::---

Solucio

nicolau@mars:/media/nicolau$ sudo chmod 777 sd2gb/
trailing "t" in file permissions

nicolau@mars:/$ ls -al ... 4 drwxrwxrwt 16 root root 4096 Apr 18 19:00 tmp

What does "t" mean ?

The d letter means it's a directory (a folder if you prefer that name). The t letter means that file is 'sticky'. Only the owner and root can delete a sticky file.

unix.stackexchange


Links


Ep ! Valid HTML 4.01!   Valid CSS! Escriu-me !
Updated 20220507 (a)  
Uf !