Need to patch using a string/variable - bash

I am writing a script to automate the process of setting up a bunch of Mac's in a computer lab.
Each system is uniquely identified and I need a method of patching a plist file in several locations with the same string that will be read from the user in the script which is a bash script
The original string is always the same. The patching string is variable depending on the identity of the system the script is being run on. This string is read from the user at the start of the script for various other purposes and stored in $macnum.
Can anybody please provide me a simple solution that can be scripted to perform the task? Thanks.

You can use some unique identifier (e.g. {{MACHINE_ID}}) in the plist and use sed to replace it:
sed -i -e 's/{{MACHINE_ID}}/'"$macnum"/g filename

sed -i "s/plist-macnum-placeholder/$macnum/g' file ...
Where -i means edit the file "in-place" and /g says make the substitution multiple times per line and can be dropped if there is only one.

The sed-based approach strager and msw gave will work fine if the plist you're changing is in XML format, but if it's in Apple's binary format it'll probably corrupt the file format. You can use plutil to convert it to XML first:
plutil -convert xml1 filename
sed -i -e "s/placeholder/$macnum/g" filename
It shouldn't be necessary to convert it back to binary format afterward, as Apple's plist frameworks read the two formats interchangeably. Another approach would be to use PlistBuddy to edit the contents of the plist (although it'll require the script to know what entries to set to what values, rather than just replacing a placeholder):
/usr/libexec/PlistBuddy -c "set :oneentry 'value including $macnum where appropriate'" filename
/usr/libexec/PlistBuddy -c "set :anotherentry 'value including $macnum where appropriate'" filename
Finally, you can do the same thing with defaults, although it requires you specify the .plist file by full path, and leave the .plist off its name:
defaults write oneentry "value including $macnum where appropriate" /path/to/filename-without-plist
defaults write anotherentry "value including $macnum where appropriate" /path/to/filename-without-plist

Related

How to write String to a text File

My question is about file handling in bash.
I want to write a string to text file in Bash script.
I have already tried
echo string>>filename.txt
your code is correct.you can write to a file using that.But you have to check the file access permission of the file you want to write the data in to.
Check following for more details.
Create text file and fill it using bash
Open and write data to text file using bash/shell scripting
That is a valid way of doing it. I would however consider this:
echo "string" >> file.txt
The quotes make it possible to handle more than one word (in the case of echo, that works anyway, but it's good practice to always use it). You should also distinguish between > and >>
> truncates the file (erases it) and replaces its contents with your string
>> on the other hand appends your string to the bottom of your file

edit/save a file within shell script

I think this question fall under pipes, am bad at it.
Using one of my shell script, a file is generated with millions of rows.
Before I can use it with another command, I need to edit this file. I need to add a text e.g 'txt' in front of every line.
What i am currently doing now is,
-exit the shell script after file is generated
-open it in vim
-use command :g/^/s//txt/g to add txt at start of each line
-save file
-use it in remaining shell script
I am sure there would be a more efficient way, which i am not aware of. thanks for the help.
As some people said in the comments, you can use GNU sed to do that:
sed -i 's/^/txt/' yourfile.txt
The -i stands for --in-place and edit your file instead of printing to stdout.

What is the standard usage argument style?

I'm making some command-line tools for some research I'm doing. I'd like these tools to follow commonly used conventions regarding command line programs in Unix.
Should I use flags or just list parameters?
program one two three
program -a one -b two -c three
Where in the list of commands does the input file normally go, or is it better to < it into the program?
What about the output filename?
Should I specify the file extension for the output format, or have my program automatically put the correct extension on?
When the user enters an invalid command, is there a prototypical "correct usage" message?
Is "--help" or "-h" required?
Also, is there some sort of header file I can include that would help with managing these?
If you're looking for a "standard", then you could do worse than look at GNU's Standards for Command Line Interfaces. Other standards are available.
As far as coding for this goes, take a look at boost::program_options. Not only will this save you rolling a lot of your own code, but it does a good job of formatting the options for presenting to the user (the prototypical "correct usage" message, you asked for).
In answer to your specific questions:
Where in the list of commands does the input file normally go, or is it better to < it into the program?
I would expect these to come at the end of a command line. Like in GNU grep. If you are only processing one file and would like to make stdin available as an input source, that would not surprise most users.
If your command processes lots of files, then it would be unusual to have to specify a switch before the filenames. Think cat.
What about the output filename?
A -o or --output option is fairly common. If your file takes exactly one input and one output, then program inputfile outputfile would not surprise many users. If no output file is specified, perhaps you'll output to stdout; that would not be unusual behaviour and would allow your users to pipe the output through other commands (such as grep, less, etc...), They could also redirect stdout to a file using >.
Should I specify the file extension for the output format, or have my program automatically put the correct extension on?
This is probably a matter for debate. If I specified an output filename, I would expect to find that file created (or replaced, after a prompt) without the program changing the name.
When the user enters an invalid command, is there a prototypical "correct usage" message?
Using GNU grep as an example again:
grep: unrecognized option '--incorrect'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
This wouldn't surprise too many users and points them in the right direction if they've made a typo without swamping them with information.
Is "--help" or "-h" required?
That depends on your customer! I find it frustrating when this option isn't available.
Usually speaking, flags are there for providing options and parameter are for passing information. If you have input,output file as command line argument, use flags like -i -o, so sequence will not matter. -h is required if you want to (and need to) give documentation.

Modify conf file with shell script

I have a default conf file that we use over and over again in our projects. And, for each project, the file has to be modified. On more than one occasion, the person editing the conf file made time consuming mistakes.
So, I wanted to write a shell script that can be called to modify the conf file.
But, being new to shell scripts, I don't know how to do this. What is the appropriate *nix tool to open a text file, find a string, replace it with another and then close the text file.
Thanks!
Eric
As noted by other commenters, sed, is the typical tool.
Here's an example of an in-place (the -i option) edit of a file:
sed -i 's/Release Two/Testing Beta/g' /path/to/file.txt
You're replacing instances of the first string, Release Two, with Testing Beta everywhere in the files. The leading s says search/replace and the trailing g says do it as many times as it can be found (the default is to do it just once.) If you want to make a backup you can call
sed -iBACKUP_SUFFIX ...
You should have a look at the sed command. It allows to edit a stream (a file for example) so you can substitute, insert, remove text.
http://www.grymoire.com/Unix/Sed.html
sed

Pre-filling a prompt in Bash

Writing a bash script, and I want to get user input. Awesome,
read -p "What directory should we save in? " -e FOLDER
Except that what I'd like to do, ideally, is have the user see something like:
What directory should we save in? /home/user/default/
with the cursor at the end of the line, and the ability to delete backwards or append or whatever. Essentially, pre-filling the user's input, but giving them the ability to edit it.
Readline obviously has the capability, but it appears to be not exposed in the read command. Any alternatives? I'd prefer to not have to use perl or such.
The constraint I'm working under is that I'm writing a single shell script that would be nice to disseminate widely, so should rely on as little pre-existing infrastructure as possible. rlwrap and read -i both work if their dependencies (rlwrap and bash version >> whatever I have, respectively) are available. Both good answers, choose whichever works for you.
$ read -p "What directory should we save in? " -i "/home/user/default/" -e FOLDER
What directory should we save in? /home/user/default/
that should work, right?
You can wrap the command in rlwrap, which provides instant readline capabilities: https://github.com/hanslub42/rlwrap
(rlwrap -P does what you want)
As far as a pure bash solution is concerned for the 3.2 line (which i am presuming you are using), I dont think its possible

Resources