I want to remove last character from a line:
[root@ozzesh ~]#df -h | awk '{ print $5 }'
Use%
22%
1%
1%
59%
51%
63%
5%
Expected result:
Use
22
1
1
59
51
63
5
sed 's/.$//'
To remove the last character.
But in this specific case, you could also do:
df -P | awk 'NR > 1 {print $5+0}'
With the arithmetic expression ($5+0) we force awk to interpret the 5th field as a number, and anything after the number will be ignored.
Note that GNU df (your -h is already a GNU extension, though not needed here) can also be told to only output the disk usage percentage:
df --output=pcent | tail -n +2 | tr -cd '0-9\n'
(tail skips the headers and tr removes everything but the digits and the line delimiters).
On Linux, see also:
findmnt -no USE%
{print +$5} will work as well...
awk implementations where that doesn't work, where the + unary operator is just ignored and doesn't force conversion of strings to numerical.
With sed, this is pretty easy:
$ cat file
Use%
22%
1%
1%
59%
51%
63%
5%
$ sed 's/.$//' file
Use
22
1
1
59
51
63
5
The syntax is s(ubstitute)/search/replacestring/. The . indicates any character, and the $ the end of the line. So .$ will remove the last character only.
In this case, your complete command would look:
df -h | awk '{ print $5}' | sed 's/.$//'
sed is redundant: it can be done in awk: df -h | awk '{gsub(/%/,""); print $5}'
I have two solutions :
cut: echo "somestring1" | rev | cut -c 2- | rev
Here you reverse the string and cut the string from 2nd character and reverse again.
sed : echo "somestring1" | sed 's/.$//'
Here you will search for regular expression .$ which means any characters followed by a last character and replace it with null // (between the two slashes)
Did you know that head and tail can work on a character basis instead of per line?
$ printf "I don't like periods." | head -c-1
I don't like periods
(BTW, printf is used here to prevent printing the "new line" character at the end of the line. If your output has a new line character and you want to remove that as well as the last non-whitespace character, use head -c-2).
This is basically the same as "Guru"'s solution using cut, but without the funky rev back and forth that they need to use because cut has no syntax for "last n things".
To iterate over a stream of lines and remove the last character of each, one might do something like this:
some-command | while read line; do echo $(head -c-2 <<<"$line"); done
&& echo "" in order to get rid of EOF char that might be printed out
echo "" prints out an zero-length string, after which the echo implementation auto-adds \n (which the printf in my example didn't on purpose, as is explained in the BTW).
echo behavior, I prefer to use it by having echo actually print the entire thing - as I demonstrated in the second example.
In awk, you could do one of
awk '{sub(/%$/,"",$5); print $5}'
awk '{print substr($5, 1, length($5)-1)}'
echo "123" | perl -ple 'chop'
12
-l already removes the newline, chop removes next char)
df -h | awk 'NR > 1{ print $5 }' | cut -d "%" -f1
cut -d '%' -f1 which is the correct answer to get everything in the line up to the first '%'.
another approach:
mapfile -t list < <(df -h)
printf '%s\n' "${list[@]%?}"
Turn it into a function:
remove_last() {
local char=${1:-?}; shift
mapfile -t list < <("$@")
printf '%s\n' "${list[@]%$char}"
}
Then call it like this:
remove_last '%' df -h
mapfile is a bash4 feature.
The catch here is that you must supply a character to remove; if you want it to just be whatever the last character happens to be then you must pass '?' or ''. quotes required.
Try with this:
df -h | awk '{ print $5 }' | sed "s/%//"
The normal use is: (ie)
VALUE=987654321
echo X123456789X | sed "s/123456789/${VALUE}/"
Response should be: X987654321X
sed -ie '$d' filename
here -i is to write changes
e means expression
$ means last line
d means delete
Note:Without -e option $ wont work
Optional: To delete 1st and last line use sed -ie '1d;$d' filename
Using Raku (formerly known as Perl_6)
~$ printf '123\n456\n789' | raku -pe '.=chop;'
12
45
78
#OR:
~$ printf '123\n456\n789' | raku -ne '.chop.put;'
12
45
78
OR:
~$ printf '123\n456\n789' | raku -pe 's/.$//;'
12
45
78
#OR:
~$ printf '123\n456\n789' | raku -ne 'put S/.$//;'
12
45
78
Just like Perl, Raku can perform sed-like substitution using the -pe (autoprinting) command-line flags, or awk-like substitution using the -ne (non-autoprinting) flags. The Raku code above works fine even if the input text contains a blank line. Note the fourth example uses Raku's new S/// "big-S" non-destructive substitution notation, which "leaves the original string intact and returns the resultant string."
OP's specific example parsing the output of df -P:
~$ df -P | raku -ne 'put .words[4].subst("%");'
#OR:
~$ df -P | raku -ne 'put .words[4].trans("%" => "");'
To skip the first line (like the excellent answer from @StéphaneChazelas), use Raku's new (pre-incrementing) anonymous variable (++$):
~$ raku -ne 'if ++$ > 1 {put .words[4].subst("%") }'
#OR:
~$ raku -ne 'if ++$ > 1 {put .words[4].trans("%" => "") }'
https://docs.raku.org/language/5to6-nutshell
https://docs.raku.org/syntax/S%2F%2F%2F%20non-destructive%20substitution
df -h | awk {'print $5'}
Filesystem Size Used Avail Use% Mounted on
devtmpfs 4,0M 0 4,0M 0% /dev
tmpfs 16G 1,6G 15G 10% /dev/shm
tmpfs 6,3G 2,3M 6,3G 1% /run
efivarfs 148K 61K 83K 43% /sys/firmware/efi/efivars
/dev/nvme0n1p3 930G 874G 55G 95% /
/dev/nvme0n1p3 930G 874G 55G 95% /home
/dev/nvme0n1p2 974M 332M 576M 37% /boot
tmpfs 16G 135M 16G 1% /tmp
/dev/nvme0n1p1 599M 43M 556M 8% /boot/efi
tmpfs 3,2G 204K 3,2G 1% /run/user/1000
/dev/nvme0n1p3 930G 874G 55G 95% /swap
df -h | awk {'print $5'} | grep -v Use | sed 's|.$||g'
0
10
1
43
95
95
37
1
8
1
95
awk {'print $5'} = only prints the 5th word
grep -v Use = removes lines with the word 'Use'
sed 's|.$||g' = removes the last character
awk {'print $5'} is silly, since the OP obviously already knows what it means. (But the braces should be inside the quotes — '{ print $5 }' — as everybody else has done it.) (2) grep -v Use is inappropriate; the OP clearly shows that the “Use” line is part of the expected/desired output. … (Cont’d)
sed 's|.$||g' is exactly the same as Stéphane Chazelas’ sed 's/.$//' answer (also given by Bernhard and Guru), except it’s meaningless to use the ‘g’ (global) modifier on an anchored substitution (one that begins with ^ or ends with $).
%sign?