I'm trying to insert a string stored in a variable with sed as follows:
sed -i "s/^GRUB_CMDLINE_LINUX_DEFAULT.*/$kernel_options/g" /etc/default/grub
Line that I am trying to replace is:
GRUB_CMDLINE_LINUX_DEFAULT=""
Variable is:
kernel_options="GRUB_CMDLINE_LINUX_DEFAULT=\"cryptdevice=${target_disk}${disk_append}2:luks:allow-discards resume=\/dev\/lvm\/swap mem_sleep_default=deep i915.enable_psr=0 i915.enable_fbc=1 i915.enable_guc=2\""
${target_disk} and ${disk_append} are determined earlier with:
target_disk=$(dialog --clear --title "Harddisk" --radiolist "Please select the target device" 0 0 0 \
$(ls /dev/sd? /dev/vd? /dev/mmcblk? /dev/nvme?n? -1 2> /dev/null | while read line; do
echo "$line" "$line" on; done) 3>&1 1>&2 2>&3)
if test $? -eq 1; then exit 1; fi
if grep -q "mmcblk" <<< $target_disk || grep -q "nvme" <<< $target_disk; then
disk_append=p
fi
I can't seem to get the sed part working, any suggestions how to improve this are appreciated.
Thank you in advance.
Thank you very much, Gordon Davisson.
It works if I create a second variable like so:
kernel_options="GRUB_CMDLINE_LINUX_DEFAULT=\"cryptdevice=${target_disk}${disk_append}2:luks:allow-discards resume=/dev/lvm/swap mem_sleep_default=deep i915.enable_psr=0 i915.enable_fbc=1 i915.enable_guc=2\""
escaped_kernel_options=$(printf '%s\n' "$kernel_options" | sed -e 's/[]\/$*.^[]/\\&/g');
sed -i "s/^GRUB_CMDLINE_LINUX_DEFAULT.*/$escaped_kernel_options/g" /etc/default/grub
How about using a and d instead of s?
sed -i "/^GRUB_CMDLINE_LINUX_DEFAULT/{
a $kernel_options
d}" /etc/default/grub
Related
This has probably been created before and better than mine. I have a directory where files are created for a few milliseconds before being removed. I researched and couldn't find what I was looking for so I made something to do it and added a few more features.
How it works:
you run the script, input the directory, and input the time you want it to run from 10 seconds to 6000 seconds (1 hour). It validates what you enter to make sure the directory is real and you don't exceed or go below that time. using sdiff -s it will compare the state of the directory when the script began to a new version of it ever 0.001 seconds. If there are changes it will tell you.
I wanted to share it since other may find it useful, and more importantly ask if you guys had improvements. I have been doing a lot of self-taught (mostly using stack exchange) bash scripting for almost a year and I really love it. I am always looking to improve me code. I am new to interactive scripts so if you guys have recommendations for input validation I'd love to hear it. I couldn't figure out how to get the "if" statements for time in seconds combined to check for anything less than 10 and greater than 6,000 despite trying a lot of things so I just made them separate. The "sed" portions are kind of wonky here and I didn't do a great job optimizing. I just worked on them until the output was what I wanted.
EDIT: I don't have inotify and I don't think I could get it on this locked down system.
#!/bin/bash
# Directory Check Script
# Created 13 Aug 2022
CLISESSID=$$
export CLISESSID
### DEFINE A LOCATION WHERE FILES CAN BE TEMPORARILY MADE ###
tmp=/tmp
temp1=$tmp/temp1.txt
temp2=$tmp/temp2.txt
echo "This script will check a directory to see if any files were added for the length of time you specify"
read -ep 'What is the full directory you would like to verify? ' dir
if [ ! -d "$dir" ] ; then
echo "Directory does not exist. Exiting."
exit
fi
read -ep '(This must be between 10-6000. i.e 5 minutes = 300, 10 minutes = 600, 1 hour = 6000)
How many seconds would you like to check for? ' seconds
if [[ "$seconds" -lt 10 ]] ; then
echo "Seconds must be between 10 and 6000"
exit
fi
if [[ "$seconds" -gt 6000 ]] ; then
echo "Seconds must be between 10 and 6000"
exit
fi
echo "checking $dir for $seconds seconds."
ls --full-time $dir | tail -n +2 > $temp1
SECONDS=0
echo "Checking for changes to $dir every 0.001 seconds for $seconds seconds."
until [[ $(ls --full-time $dir | tail -n +2) != $(cat "$temp1") ]] > /dev/null 2>&1
do
if (( SECONDS > $seconds ))
then
echo "Exceded defined time of $seconds seconds. Exiting."
exit 1
fi
sleep 0.001
done
ls --full-time $dir | tail -n +2 > $temp2
if [[ $(sdiff -w 400 -s $temp1 $temp2 | grep " |" | wc -l) -gt 0 ]] ; then
echo "
File has been modified in $dir:"
sdiff -w 400 -s $temp1 $temp2 | sed 's/|/\n/' | sed 's/^ *//g' | sed '1~ i Before:' | sed '3~ i After:' | sed 's/^ *//g' | sed -e 's/^[ \t]*//'
fi
if [[ $(sdiff -w 400 -s $temp1 $temp2 | grep " >" | wc -l) -gt 0 ]] ; then
echo "
File has been added to $dir:"
sdiff -w 400 -s /tmp/temp1.txt /tmp/temp2.txt | sed 's/>/\n/' | grep -v " |" | sed 's/^ *//g' | sed '1~ i Added file:' | sed 's/^ *//g' | sed -e 's/^[ \t]*//' | sed '/./!d'
fi
if [[ $(sdiff -w 400 -s $temp1 $temp2 | grep " <" | wc -l) -gt 0 ]] ; then
echo "
File has removed modified in $dir:"
sdiff -w 400 -s $temp1 /$temp2 | sed 's/</\n/' | grep -v " |" | sed 's/^ *//g' | sed '1~ i Removed file:' | sed 's/^ *//g' | sed -e 's/^[ \t]*//' | sed '/./!d' | sed 's/ *$//'
fi
rm -f $temp1 $temp2
I'm trying to grep multiple arguments in shell.
I put orders like ./script arg1 arg2.. argN
And I want them to act
egrep -i "arg1" mydata | egrep -i "arg2" | ... egrep -i "argN" | awk -f display.awk
in order to match patterns in AND format.
What's wrong in my process?
Is it even right to code like
egrep -i "arg1" mydata | egrep -i "arg2" | ... egrep -i "argN" | awk -f display.awk
to get multiple patterns in AND format??
if [ $# -eq 0 ]
then
echo "Usage:phone searchfor [...searchfor]"
echo "(You didn't tell me what you want to search for.)"
exit 0
else
for arg in $*
do
if [ $arg -eq $1 ]
then
egrep -i "arg" mydata |
else
egrep -i "arg" |
fi
done
awk -f display.awk
fi
If my data has
'happy sunny bunny',
'sleepy bunny',
and 'happy sunny'
I want them to perform if I tried ./script happy sunny bunny
then only
'happy sunny bunny'
comes out.
and if i tried ./script bunny then
'happy sunny bunny'
'sleepy bunny'
both coming out.
The immediate fix is to move the pipe character to after the done.
Also, you should loop over "$#" to preserve the quoting of your arguments, and generally quote your variables.
if [ $# -eq 0 ]
then
# print diagnostics to stderr
echo "Usage: phone searchfor [...searchfor]" >&2
echo "(You didn't tell me what you want to search for.)" >&2
exit 0
fi
for arg in "$#"
do
# Add missing dash before eq
if [ "$arg " -eq "$1" ]
then
# Surely you want "$arg" here, not the static string "arg"?
grep -E -i "$arg" mydata
else
grep -E -i "$arg"
fi
done |
awk -f display.awk
The overall logic still seems flawed; you will be grepping standard input for the first argument if there are more than two arguments. Perhaps you want to add an option to allow the user to specify an input file name, with - to specify standard input? And then all the regular arguments will be search strings, like the usage message suggests.
If indeed the intent is to loop over all the arguments to produce a logical AND, try this:
also () {
local what
what=$1
shift
if [ $# -gt 0 ]; then
grep -E -i "$what" | also "$#"
else
grep -E -i "$what"
fi
}
also "$#" <mydata | awk -f display.awk
... though a better implementation might be to build a simple Awk or sed script from the arguments:
script='1'
for arg in "$#"; do
script="$script && tolower(\$0) ~ tolower(\"$arg\")"
done
awk "$script" | awk -f display.awk
This breaks down if the search phrases could contain regex specials, though (which of course is true for the grep -E version as well; but then you could easily switch to grep -F).
Merging the two Awk scripts into one should probably not be hard either, though without seeing display.awk, this is speculative.
You can solve it recursively:
#! /bin/bash
if (( $# == 0)); then
exec cat
else
arg=$1; shift
egrep "$arg" | "$0" "$#"
fi
The recursion ends, if the script is called with no arguments. In this case it behaves like cat. In your example you can put your awk there. If the script is called with one or more arguemnts, it calles egrep with the first argument ($1) and passes the remaining arguments ($# after shift) to itself ($0).
Example:
$ ./recursive-egrep sys < /etc/passwd
sys:x:3:3:sys:/dev:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
$ ./recursive-egrep sys no < /etc/passwd
sys:x:3:3:sys:/dev:/usr/sbin/nologin
Use G from https://gitlab.com/ole.tange/tangetools/tree/master/G which does this (except for the awk part).
SYNOPSIS
G [[grep options] string] [[grep options] string] ...
DESCRIPTION
G is a shorthand of writing (search for single lines matching expressions):
grep --option string | grep --option2 string2
or with -g (search full files matching expressions):
find . -type f | xargs grep -l string1 | xargs grep -l string1
#!/bin/sh -x
if [[ $# -eq 0 ]];then
echo "usage: makeSoln <customer name>"
exit
fi
echo "Customer Name is set to : $1"
if [ -d "$1" ]; then
echo "Solution for $1 already exists!! Please delete it before running this."
exit 1;
fi
if [ -e "$1" ]; then
echo "A file by name '$1' exists!! Please delete it before running this."
exit 1;
fi
cp -R SolnTemplate $1
cd $1
find . -name "pom.xml" | xargs sed -i xx 's/SolnTemplate/'$1'/g'
When i given this and execute this file i am gettting this error:
+ xargs sed -e xx s/SolnTemplate/Reliance/g
sed: -e expression #1, char 2: extra characters after command
To begin, replace:
find . -name "pom.xml" | xargs sed -i xx 's/SolnTemplate/'$1'/g'
With:
find . -name "pom.xml" | xargs sed -ixx 's/SolnTemplate/'$1'/g'
The above removes the space between -i and xx. Because you are on Linux, you are using GNU sed and, unlike BSD sed, it does not accept a space between -i and the backup suffix.
Also, just in case $1 includes a space in the name, it should be enclosed in double-quotes:
find . -name "pom.xml" | xargs sed -ixx 's/SolnTemplate/'"$1"'/g'
This still requires care that you don't unintentionally include any sed-active characters in $1.
i didnt go over all of the script, but this command:
sed -i xx 's/SolnTemplate/'$1'/g'
should be:
sed -ixx 's/SolnTemplate/"$1"/g'
because the ' is from outside, you need to put in the inside "
I have a long string like following:
string='<span id="/yourid/12345" class="noname">lala1</span><span id="/yourid/34567" class="noname">lala2</span><span id="/yourid/39201" class="noname">lala3</span>'
The objective is to loop through each of the 'yourid' and echo the id 12345, 34567 and 39201 for further processing. How can this be achieve through bash shell?
GNU grep:
grep -oP '(?<=/yourid/)\d+' <<< "$string"
12345
34567
39201
Use a real XML parser. For instance, if you have XMLStarlet installed...
while read -r id; do
[[ $id ]] || continue
printf '%s\n' "${id#/yourid/}"
done < <(xmlstarlet sel -m -t '//span[#id]' -v ./#id -n <<<"<root>${string}</root>")
With Perl:
declare -a ids
ids=( $(perl -lne 'while(m!yourid/(\w+)!g){print $1}' <<< "$string") )
echo ${ids[#]}
The same way it’s possible to write a file that autoextracts itself, I’m looking for a way to autorun a program within a script (or whatever it needs). I want the program part of the script, because I just want one file. It’s actually a challenge: I have a xz compressed program, and I wanna be able to run it without any intervention of the xz program by the user (just a ./theprogram).
Any idea?
Autorun after doing what? Login? Call it in ~/.bashrc. During boot? Write an appropriate /etc/init.d/yourprog and link it to the desired runlevel. Selfextract? Make it a shell archive (shar file). See the shar utility, http://linux.die.net/man/1/shar
Sorry but I was just thinking... Something like this would not work?
(I am assuming it is a script...)
#!/bin/bash
cat << 'EOF' > yourfile
yourscript
EOF
chmod +x yourfile
./yourfile
Still, it's pretty hard to understand exactly what you are trying to do... it seems to me that the "autorun" is pretty similar to a "call the program from within the script"..
I had written a script for this. This should help:
#!/bin/bash
set -e
payload=$(cat $0 | grep --binary-files=text -n ^PAYLOAD: | cut -d: -f1 )
filaname=`head $0 -n $payload | tail -n 1 | cut -d: -f2-`
tail -n +$(( $payload + 1 )) $0 > /tmp/$filaname
set +e
#Do whatever with the payload
exit 0
#Command to add payload:
#read x; ls $x && ( cp 'binary_script.sh' ${x}_binary_script.sh; echo $x >> ${x}_binary_script.sh; cat $x >> ${x}_binary_script.sh )
#Note: Strictly NO any character after "PAYLOAD:", not even newline...
PAYLOAD:
Sample usage:
Suppose myNestedScript.sh contains below data:
#!/bin/bash
echo hello world
Then run
x=myNestedScript.sh; ls $x && ( cp 'binary_script.sh' ${x}_binary_script.sh; echo $x >> ${x}_binary_script.sh; cat $x >> ${x}_binary_script.sh )
It will generate below file, which you can directly execute. Upon executing below file, it will extract myNestedScript.sh to /tmp & run that script.
#!/bin/bash
set -e
payload=$(cat $0 | grep --binary-files=text -n ^PAYLOAD: | cut -d: -f1 )
filaname=`head $0 -n $payload | tail -n 1 | cut -d: -f2-`
tail -n +$(( $payload + 1 )) $0 > /tmp/$filaname
set +e
chmod 755 /tmp/$filaname
/tmp/$filaname
exit 0
PAYLOAD:myNestedScript.sh
#!/bin/bash
echo hello world