Bash oneliners




Check if input is integer

re='^[0-9]+$'
[[ $input =~ $re ]] && echo integer || echo "NOT" >&2

 


 

Concatenate list of lines to single line

cat <( egrep -o '^[^ ]+ ' /etc/passwd )\
	| while read line; do echo -n "$line "; done

 


 

Convert float to integer

printf -v int %.0f "$float"

or

float=1.23
int=${float%.*}

 


 

Convert lines to space separated

i.e. items separated by linebreaks to space separated

For a file:

cat tmp.txt | sed ':a;N;$!ba;s/\n/ /g' > tmp2.txt

For a variable:

var=`echo -e "something\nover\nthe\nrainbow"`
echo "$var"; echo; sed ':a;N;$!ba;s/\n/ /g' <<<"${var}"

outputs

something
over
the
rainbow

something over the rainbow

 


 

Copy a whole directory preserving permissions

This is my favourite bash one-liner of all time:

(cd /source/dir && tar cpf - . ) | (cd /target/directory && tar xpf -)

 


 

Create empty image

convert -size 1x1 xc:transparent pixel.png

 


 

Date from epoch seconds

date -d  @1234567890

Sat 14 Feb 2009 12:31:30 AM CET

 


 

DEC-HEX conversions

From decimal to hexadecimal

echo "obase=16;4095" | bc
printf "%x\n" 4095

From hexadecimal to decimal

echo "ibase=16;FFF" | bc
printf "%d\n" 0xfff

 


 

grep axios `find . -maxdepth 2 -type f`

 


 

Disable history (temporarily)

set +o history # turn off
set -o history # turn on

 


 

Display weather from console

According to this posting, simply by using

curl wttr.in

e.g.

curl wttr.in/offenbach

it is possible to display the current weather and forecast:

Weather report: offenbach

     \   /     Sunny
      .-.      15 °C          
   ― (   ) ―   ↙ 2 km/h       
      `-’      10 km          
     /   \     0.0 mm         
                                                       ┌─────────────┐                                                       
┌──────────────────────────────┬───────────────────────┤  Mon 18 May ├───────────────────────┬──────────────────────────────┐
│            Morning           │             Noon      └──────┬──────┘     Evening           │             Night            │
├──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│    \  /       Partly cloudy  │    \  /       Partly cloudy  │    \  /       Partly cloudy  │    \  /       Partly cloudy  │
│  _ /"".-.     0..17 °C       │  _ /"".-.     0..21 °C       │  _ /"".-.     0..21 °C       │  _ /"".-.     0..17 °C       │
│    \_(   ).   ↖ 4-5 km/h     │    \_(   ).   ↗ 6-7 km/h     │    \_(   ).   ↘ 10-13 km/h   │    \_(   ).   ↘ 8-14 km/h    │
│    /(___(__)  10 km          │    /(___(__)  10 km          │    /(___(__)  10 km          │    /(___(__)  10 km          │
│               0.0 mm | 0%    │               0.0 mm | 0%    │               0.0 mm | 0%    │               0.0 mm | 0%    │
└──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┘
                                                       ┌─────────────┐                                                       
┌──────────────────────────────┬───────────────────────┤  Tue 19 May ├───────────────────────┬──────────────────────────────┐
│            Morning           │             Noon      └──────┬──────┘     Evening           │             Night            │
├──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│    \  /       Partly cloudy  │    \  /       Partly cloudy  │    \  /       Partly cloudy  │    \  /       Partly cloudy  │
│  _ /"".-.     0..19 °C       │  _ /"".-.     0..23 °C       │  _ /"".-.     0..21 °C       │  _ /"".-.     0..18 °C       │
│    \_(   ).   ↗ 3-4 km/h     │    \_(   ).   ↘ 4 km/h       │    \_(   ).   ↘ 13-18 km/h   │    \_(   ).   ↖ 12-17 km/h   │
│    /(___(__)  10 km          │    /(___(__)  10 km          │    /(___(__)  10 km          │    /(___(__)  10 km          │
│               0.0 mm | 0%    │               0.0 mm | 0%    │               0.0 mm | 0%    │               0.0 mm | 0%    │
└──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┘
                                                       ┌─────────────┐                                                       
┌──────────────────────────────┬───────────────────────┤  Wed 20 May ├───────────────────────┬──────────────────────────────┐
│            Morning           │             Noon      └──────┬──────┘     Evening           │             Night            │
├──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│    \  /       Partly cloudy  │    \  /       Partly cloudy  │    \  /       Partly cloudy  │    \  /       Partly cloudy  │
│  _ /"".-.     0..18 °C       │  _ /"".-.     0..21 °C       │  _ /"".-.     0..22 °C       │  _ /"".-.     0..19 °C       │
│    \_(   ).   ↓ 10-12 km/h   │    \_(   ).   ↓ 12-13 km/h   │    \_(   ).   ↓ 11-15 km/h   │    \_(   ).   ↓ 8-13 km/h    │
│    /(___(__)  10 km          │    /(___(__)  10 km          │    /(___(__)  10 km          │    /(___(__)  10 km          │
│               0.0 mm | 0%    │               0.0 mm | 0%    │               0.0 mm | 0%    │               0.0 mm | 0%    │
└──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┘
Location: Offenbach am Main, Regierungsbezirk Darmstadt, Hessen, Deutschland [50.088766,8.766286]

Follow @igor_chubin for wttr.in updates

d47c356626554a9397980bf44129d400

 


 

Expand IP CIDR block

The following lists all IP addresses

IP="87.251.74.0/24"
nmap -sL $IP | awk '/Nmap scan report/{print $NF}' | tr -d '()' | more

outputs

87.251.74.0
87.251.74.251
87.251.74.252
...
87.251.74.253
87.251.74.254
87.251.74.255

 


 

Find all text (ascii) files

find /var/www/html/ -type f \
	-exec grep -Iq . {} \; \
	-and -print

According to the reference, the -I option to grep tells it to immediately ignore binary files.

 


 

Find files with illegal characters

E.g. those not permitted in a Windows in filename

find . -name "*[<>:\\|?*]*" 

 


 

Find newest file

This may take long!

find . -type f -exec stat --format '%Y :%y %n' "{}" \; \
	| sort -nr | cut -d: -f2- | head

 


 

Generate a series of zero padded integers

for i in $(seq -f "%05g" 10 15); do echo $i; done

OR also

printf "%05d\n" $i

produces

00099

Using the -v flag stores the output in another variable:

i=99
printf -v j "%05d" $i
echo $j

See this resource.

 


 

Get lastmod of file in epoch seconds using stat

stat -c %y FILE

 


 

Grep out comments and blank lines

egrep -v "^#|^$" FILE | less
# OR
egrep -v "^[#;]+|^$" FILE | less

 


 

Handling files/directories with spaces using find

find . -print0 | while IFS= read -d $'\0' file; do echo $file; done

Notes:

See here for more detailed explanation.

 


 

Increment a variable

In bash there are several ways to increment a variable:

var=$((var+1))
((var=var+1))
((var+=1))
((var++))
((++var))
let "var+=1"
let "var++"
let "++var"

 


 

IP address oneliners

Resolve hostname to IP address

getent hosts unix.stackexchange.com | \
	awk '{ print $1 ; exit }'

exit causes only the first IP to be returned

Get the external IP address

curl -s checkip.dyndns.org | \
	sed -e 's/.*Current IP Address: //' -e 's/<.*$//'

or shorter

wget http://ipinfo.io/ip -qO -

Extract IP address from some text

echo $TEXT | grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'

 


 

JSON inplace update using jq

Given a file package.json containing JSON code, the following adds a new key and value to “scripts”:

json="$(jq '.scripts.dev="netlify dev"' package.json)" && \
	echo "$json" > package.json

such that, e.g.

{
  "name": "test_app",
  "version": "1.0.0",
  "main": "app.js",
  "license": "MIT",
  "dependencies": {
    "faunadb": "^4.4.1"
  }
}

becomes

{
  "name": "test_app",
  "version": "1.0.0",
  "main": "app.js",
  "license": "MIT",
  "dependencies": {
    "faunadb": "^4.4.1"
  },
  "scripts": {
    "dev": "netlify dev"
  }
}

 


 

List the subdirectories in a tarball

tar tfz tarball.tgz --exclude '*/*'

The --exclude option to excludes contents within a subdirectory.

 


 

Match string

string='Some not very long string';
[[ $string == *"very long"* ]] && echo match || echo NOT # match
[[ $string == *"not long"* ]] && echo match || echo NOT # NOT

Also using REGEX match function with group capture:

line="## 13. Check if an object is a Promise"
[[ "$line" =~ ^##' '+([0-9]+)\.' '+(.+) ]] && { \
	echo $line; \
	echo ${BASH_REMATCH[1]}; echo ${BASH_REMATCH[2]}; \
}

outputs

## 13. Check if an object is a Promise
13
Check if an object is a Promise

 


 

Mount partition from commandline

LABEL=TV_ARC
udisksctl mount -b $(findfs LABEL=$LABEL)

List all known partitions with their respective labels

lsblk --fs

 


 

Output history without line numbers

i.e. select only characters from pos 8

history | cut -c 8-

 


 

Output whitepace as control characters

E.g. to show the contents of the special variable IFS

printf "%q" "$IFS"

displays

$' \t\n'

 


 

Pipe a list of files to be added to a tarball

find /path/to/files -name \*.txt | tar -cvf allfiles.tar -T -

 


 

Pipe a webcam shot to Imagemagick display

Requires that fswebcam is installed:

fswebcam --device=/dev/video1 --png=0 - | display

 


 

https://makandracards.com/makandra/24202-linux-how-to-print-pdf-files-from-the-command-line

lp example.pdf

 


 

Recursively find the newest file in a subdirectory

find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "

 


 

Remove leading zeros from a variable

# Removes 1 or more longest occurrences from the beginning of the string
epoch="1593151200"
hour=`date +%H --date=@${epoch}` # "08"
hour=${hour##+(0)} # "8"

Ref: http://tldp.org/LDP/abs/html/string-manipulation.html

 


 

Replace forward with back slash in filepath

echo "$filepath" | sed -E 's/\//\\/g'; done

 


 

Save output to an array using IFS

IFS=$'\n'
arr=($(grep -n "search term" file.txt | sed 's/:.*//'))
unset IFS

 


 

Show CPU/memory intensive processes

# top 10 memory consuming processes
ps -auxf | sort -nr -k 4 | head -10

# top 10 CPU consuming processes
ps -auxf | sort -nr -k 3 | head -10

 


 

Show currently installed packages on Debian/Ubuntu system

Complete list

/usr/bin/dpkg-query -Wf '${Package}\t${Version}\n'

List packages without reverse dependencies

for target in `dpkg -l | grep '^ii' | awk '{ print \$2 }'`; do
   if [ "`apt-cache rdepends --installed $target | wc -l`" = "2" ]; then
      echo "$target"
   fi
done

Source: https://www.client9.com/debian-find-packages-without-reverse-dependencies/

 


 

Show seconds remaining in the minute

echo $(( 61-$(echo $(date +%S | sed -e 's/^0//')) ))

 


 

Function or one-liner to slugify a text string

slugify() { echo "$1" | iconv -t ascii//TRANSLIT | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z; }

 


 

Sort output by column

e.g. 2nd column

du . -hk --max-depth=2 | sort -k2

 


 

Trim leading or trailing whitespace using sed

# leading space
echo '     30 01' | sed -e 's/^[[:space:]]*//'

# trailing spaces
echo " test test test " | sed 's/ *$//'

 


 

Use bc to do calculations

echo "469958656/39.905" | bc -l

11776936.62448314747525372760

 


 

Use sed to insert lines before or after a match

Given a file, FILE, containing this content:

# Header 1 - Primary

Some detail

then this sed command will append (in place) AFTER the line containing # Header 1 - Primary the text \n## Section Header (note the leading linefeed which needs to be escaped):

sed -i '/# Header 1.*/a \\n## Section Header' FILE

resulting in

# Header 1 - Primary

## Section Header

Some detail

To insert BEFORE the matched text, use the switch /i instead.

To do only ONE replacement,

sed -i '0,/# Header 1.*/a \\n## Section Header' FILE

See here for more detail and examples using sed.

 


 

Useful applications of netcat

Check if a computer is reachable via SSH with netcat

A non-zero result means not available:

nc -z HOST PORT > /dev/null
echo $?

or

nc -z HOST PORT && echo available || echo UNAVAILABLE

Ref: https://unix.stackexchange.com/a/6811

Check for an open port with netcat

nc -zv HOST PORT1 PORT2 PORT3

e.g.

nc -zv 7.19.8.89 8222 8223

results in

Connection to 7.19.8.89 8222 port [tcp/*] succeeded!
nc: connect to 7.19.8.89 port 8223 (tcp) failed: No route to host

indicating first port is open while second is not.

Using netcat to transfer files

On the SENDER (with IP 192.168.178.4):

tail -f /var/log/pihole.log | nc -vv -l -p 4567

outputs

Listening on [0.0.0.0] (family 2, port 4567)

Then on the RECEIVER

nc -vv 192.168.178.4 4567 # output on STDOUT
# OR to save to a local file
nc -vv 192.168.178.4 4567 > saveToFile

outputs

Connection to 192.168.178.41 4567 port [tcp/*] succeeded!
Aug  9 14:33:26 dnsmasq[10974]: reply mesu-cdn.origin-apple.com.akadns.net is <CNAME>
Aug  9 14:33:26 dnsmasq[10974]: reply mesu.apple.com.edgekey.net is <CNAME>
...

Once the client disconnects, so does the server (SENDER).

SSH port 22 honeypot using netcat

sudo -- bash -c 'while true; do echo started; \
	netcat -l -p 22 >> /tmp/netcat.log; done'

Simple webserver with netcat

nc -vv -l 127.0.0.1 -p 4567 < index.html

To serve a JSON file as a simple RESTful API server:

FILE="content.json"
PORT=3333
while :; do \
  echo -en "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type: application/json; charset=utf-8\r\n\r\n$(<$FILE)\r\n\r\n" \
    | nc -q 1 -k -l -p $PORT; \
done

Transfer whole directory using netcat

On the SENDER (with IP 192.168.178.4):

tar -cvf - ~/some_dir | nc -vv -l -p 9876

Then on the RECEIVER:

cd /tmp; nc 192.168.178.4 9876 | tar -xvf -

Testing network speed with netcat

This may require installation of netcat-traditional package on Ubuntu.

On the SENDER (with IP 192.168.178.4):

time nc -vv -n -l -p 7845 >/dev/null

Then on the RECEIVER:

time yes | nc.traditional -vv -n 192.168.178.4 7845 >/dev/null

Then after some time press Ctrl+C to end the connection. Something like the following will be displayed:

(UNKNOWN) [192.168.178.41] 7845 (?) open
^C sent 469958656, rcvd 0


real	0m39,905s
user	0m0,373s
sys	0m1,771s

i.e. ~ (469.958.656 * 8)/1000/1000 ~= 3760 Mb/sec

 


 

Using cut and handling multiple spaces

ps aux | grep -v grep | tr -s ' ' | cut -d' ' -f3,11
		 ^^^^^^^^^^^^   ^^^^^^^^^   ^^^^^^^^^^^^^
			   |            |             |
			   |            |    get 3rd & 11th fields
			   |            |
			   |       squeeze spaces
			   |
		 grep out 'grep'

 


 

View image via SSH

This requires that the program eog is installed locally:

cd /tmp && FIFO=$(mktemp -u); \
	ssh remote_host "cat /remote/path/to/image" > "$FIFO"; \
	eog  "$FIFO" && rm "$FIFO";

 


 

Website spider using wget

url="https://marcgreyling.com"
wget --spider --force-html -r -l2 $url 2>&1 | grep '^--' | awk '{ print $3 }' | sort -u > urls_`date +%Y%m%d_%Hh%M`.txt