I have a variable in bash number which contains values 01, 02, 03, 04, 05, 06, 07, 08, 09, 010, 011, 012.
I would like to remove the leading zeros before 010, 011 and 012. I only want to remove the leading zeroes if the number is a double digit number.
How can I achieve this?
Thanks in advance!
Try:
a="012"
printf '%02d\n' "$((10#${a}))"
12
Another way:
a="014"
printf "%02d\n" $(echo "obase=10;$a" |bc)
14
another one:
[[ $a =~ ^0+[1-9]{2,}$ ]] && a="$(echo $((10#${a})))"
echo $a
This one will remove all 0s from beginning for 2 or more non-zero digit numbers.
Related
i'am currently trying to count +1 to a variable which could contain either
02
15
i use the following line to count one up, but the output seems not to be two digit. So if 02 is the $version and count one up, it will give the output "3" and not "03". Sure if its already two digit, it works.
$((echo $version) + 01))
how can I get bash to count with two digits and output it correctly?
Use printf to format a number. Also, note that 08 fails in numeric expressions, as numbers starting with 0 are interpreted as octal.
#!/bin/bash
shopt -s extglob
for n in 02 08 15 001; do
i=${n##+(0)} # Remove leading zeros. Needs the extglob.
length=${#n}
printf "%0${length}d\\n" $((i + 1))
done
I wrote below piece of code to calculate the date after a given date:
date=$DATE_FINAL
declare -a max_month=(0 31 28 31 30 31 30 31 31 30 31 30 31)
eval $(echo $date|sed 's!\(....\)\(..\)\(..\)!year=\1;month=\2;day=\3!')
(( year4=year%4 ))
(( year100=year%100 ))
(( year400=year%400 ))
if [ \( $year4 -eq 0 -a \
$year100 -ne 0 \) -o \
$year400 -eq 0 ]
then
declare -a max_month=(0 31 28 31 30 31 30 31 31 30 31 30 31)
fi
day=$((day+1))
if [ $day -gt ${max_month[$month]} ] >| /wload/baot/home/baoted9/logs_bde27_conversion_1/ataa_display.logs 2>&1
then
day=1
month=$((month+1))
if [ $month -gt 12 ]
then
year=$((year+1))
month=1
fi
fi
if [ $month -eq "08" ] || [ $month -eq "09" ]
then
future_date_final=$(echo $year"$month"$day)
else
future_date_final=$(printf "%4.4d%2.2d%2.2d" $year $month $day)
fi
echo "this is your final business date $future_date_final"
It calculates the date correctly however throws an error at the end of the code as below -
line 79: 08: value too great for base (error token is "08")
It just looks too ugly, not sure how to remove it as otherwise code is working fine, tried redirecting it to a log file still appearing.
Also, I am facing issue with below code for a plain cd command with code highlighted in red -
echo "pset date $Param_date_1"
cd /wload/baot/home/baotasa0/sandboxes_finance/ext_ukba_bde/pset >| /wload/baot/home/baoted9/logs_bde27_conversion_1/at_display.logs 2>&1
sh UKBA_publish.sh UKBA $Param_date_1 3 >| /wload/baot/home/baoted9/logs_bde27_conversion_1/ate_display.logs 2>&1
Error is -
./auto2.sh: line 190: syntax error: unexpected end of file
The problem is, that if you're using $((val+1)) where $val is beginning with a 0, then bash isn't operating on decimal base but on octal base. Since 08 isn't a valid number in octal base, it complains.
You can force decimal representation by writing
$((10#$val+1))
Please note, that by doing so, any preceding zeros are removed. If you need to have a representation with preceding zero, just use
val=$(printf '%02d' $((10#$val+1)))
For reference, see the bash manual:
Constants with a leading 0 are interpreted as octal numbers. A leading ‘0x’ or ‘0X’ denotes hexadecimal. Otherwise, numbers take the form [base#]n, where the optional base is a decimal number between 2 and 64 representing the arithmetic base, and n is a number in that base. If base# is omitted, then base 10 is used. When specifying n, the digits greater than 9 are represented by the lowercase letters, the uppercase letters, ‘#’, and ‘_’, in that order. If base is less than or equal to 36, lowercase and uppercase letters may be used interchangeably to represent numbers between 10 and 35.
P.S.: This is a very good article about falsehoods programmers believe about time I had to read myself. If possible, try to use date -d instead of doing manual date arithmetic. You can use for instance date -d "+5 days" +%d.%m.%Y to get the date in five days.
I have an input as below:
Sep 9 09:22:11
Hello
Hello
Sep 9 10:23:11
Hello
Hello
Hello
Sep 10 11:23:11
I expect the output as below: (the same contiguous lines are replaced by only one line)
Sep 9 09:22:11
Hello
Sep 9 10:23:11
Hello
Sep 10 11:23:11
Could anyone help me solving this one fast using shell or awk ?
Using awk you can do this:
awk '$0 != prev; {prev=$0}' file
Sep 9 09:22:11
Hello
Sep 9 10:23:11
Hello
Sep 10 11:23:11
Command Breakup:
$0 != prev; # if previous line is not same as current then print it
{prev=$0} # store current line in a variable called prev
To remove repeats of lines, use uniq:
uniq File
With your sample input, for example:
$ uniq File
Sep 9 09:22:11
Hello
Sep 9 10:23:11
Hello
Sep 10 11:23:11
Although its name may imply that uniq concerns itself with unique lines, it does not: it looks for adjacent repeated lines and, by default, removes the repeats.
Just because you asked for shell too, though the given answers are all better solutions -
last=''
while read line
do if [[ "$line" -eq "$last" ]]
then continue
else echo "$line"
last="$line"
fi
done < infile
This is simple, clear, and likely slower than either awk or uniq.
I'm looking for help with a bash script to do some renaming of files for me. I don't know much about bash scripting, and what I have read is overwhelming. It's a lot to know/understand for the limited applications I will probably have.
In Dropbox, my media files are named something like:
Photo Jul 04, 5 49 44 PM.jpg
Video Jun 22, 11 21 00 AM.mov
I'd like them to be renamed in the following format: 2015-07-04 1749.ext
Some difficulties:
The script has to determine if AM or PM to put in the correct 24-hour format
The year is not specified; it is safe to assume the current year
The date, minute and second have a leading zero, but the hour does not; therefore the position after the hour is not absolute
Any assistance would be appreciated. FWIW, I'm running MacOS.
Mac OSX
This uses awk to reformat the date string:
for f in *.*
do
new=$(echo "$f" | awk -F'[ .]' '
BEGIN {
split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",month)
for (i in month) {
nums[month[i]]=i
}
}
$(NF-1)=="PM" {$4+=12;}
{printf "%s 2015-%02i-%02i %02i%02i.%s",$1,nums[$2],$3,$4,$5,$8;}
')
mv "$f" "$new"
done
After the above was run, the files are now named:
$ ls -1 *.*
Photo 2015-07-04 1749.jpg
Video 2015-06-22 1121.mov
The above was tested on GNU awk but I don't believe that I have used any GNU-specific features.
GNU/Linux
GNU date has a handy feature for interpreting human-style date strings:
for f in *.*
do
prefix=${f%% *}
ext=${f##*.}
datestr=$(date -d "$(echo "$f" | sed 's/[^ ]* //; s/[.].*//; s/ /:/3; s/ /:/3; s/,//')" '+%F %H%M')
mv "$f" "$prefix $datestr.$ext"
done
Here is an example of the script in operation:
$ ls -1 *.*
Photo Jul 04, 5 49 44 PM.jpg
Video Jun 22, 11 21 00 AM.mov
$ bash script
$ ls -1 *.*
Photo 2015-07-04 1749.jpg
Video 2015-06-22 1121.mov
While not a simple parse and reformat for date, it isn't that difficult. The bash string tools of parameter expansion/substring removal are all you need to parse the pieces of the date into a format that date can use to output a new date string in the format for use in a filename. (see String Manipulation ) date -d is used to generate a new date string based on the contents of the original filename.
Note: the following presumes the dropbox filenames are in the format you have specified. (it doesn't care what the first part of the name or extension is as long as it matches the format you have specified) Here is an example of properly isolating the pieces of the filename needed to generate a date in the format specified)
Further, all spaces have been removed from the filename. While you originally showed a space between the day and hours, I will not provide an example of poor practice by inserting a space in a filename. As such, the spaces have been replaced with '_' and '-':
#!/bin/bash
# Photo Jul 04, 5 49 44 PM.jpg
# Video Jun 22, 11 21 00 AM.mov
# fn="Photo Jul 04, 5 49 44 PM.jpg"
fn="Video Jun 22, 11 21 00 AM.mov"
ext=${fn##*.} # determine extension
prefix=${fn%% *} # determine prefix (Photo or Video)
datestr=${fn%.${ext}} # remove extension from filename
datestr=${datestr#${prefix} } # remove prefix from datestr
day=${datestr%%,*} # isolate Month and date in day
ampm=${datestr##* } # isloate AM/PM in ampm
datestr=${datestr% ${ampm}} # remove ampm from datestr
timestr=${datestr##*, } # isolate time in timestr
timestr=$(tr ' ' ':' <<<"$timestr") # translate spaces to ':' using herestring
cmb="$day $timestr $hr" # create combined date/proper format
## create date/time string for filename
datetm=$(date -d "$cmb" '+%Y%m%d-%H%M')
newfn="${prefix}_${datetm}.${ext}"
## example moving of file to new name
# (assumes you handle the path correctly)
printf "mv '%s' %s\n" "$fn" "$newfn"
# mv "$fn" "$newfn" # uncomemnt to actually use
exit 0
Example/Output
$ bash dateinfname.sh
mv 'Video Jun 22, 11 21 00 AM.mov' Video_20150622-1121.mov
I have the following line:
Jan 13, 2014 1:01:31 AM
I want to remove the seconds part of the line. The result should be:
Jan 13, 2014 1:01 AM
How can this be done ?
Use parameter expansion:
t='Jan 13, 2014 1:01:31 AM'
ampm=${t: -2} # last two characters
echo "${t%:*} $ampm" # remove everything after the last :
Using sed:
s='Jan 13, 2014 1:01:31 AM'
sed 's/:[0-9]*\( [AP]M\)/\1/' <<< "$s"
Jan 13, 2014 1:01 AM
you can give this a try:
sed 's/:[^:]* / /'
with your example:
kent$ (master|✚2) echo "Jan 13, 2014 1:01:31 AM"|sed 's/:[^:]* / /'
Jan 13, 2014 1:01 AM
Another way, if your date command is gnu date which support -d option.
$ str="Jan 13, 2014 1:01:31 AM"
$ date -d "$str" +"%b %d, %Y %l:%M %p"
Jan 13, 2014 1:01 AM